# Copyright (c) Facebook, Inc. and its affiliates.
# All rights reserved.
#
# Copyright 2019 Google LLC
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

CMAKE_MINIMUM_REQUIRED(VERSION 3.15 FATAL_ERROR)

# Allow specifying -D<PackageName>_ROOT.
CMAKE_POLICY(SET CMP0074 NEW)

# MSVC runtime library flags are selected by an abstraction.
CMAKE_POLICY(SET CMP0091 NEW)

# ---[ Project and semantic versioning.
PROJECT(XNNPACK C CXX ASM)

# --[ Use ccache if available
FIND_PROGRAM(CCACHE_BINARY "ccache")
IF(CCACHE_BINARY)
  MESSAGE(STATUS "Using ccache: ${CCACHE_BINARY}")
  SET(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_BINARY}" CACHE STRING "CXX compiler launcher" FORCE)
  SET(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_BINARY}" CACHE STRING "C compiler launcher" FORCE)
  IF(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
    STRING(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
    STRING(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
    STRING(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
    STRING(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
    STRING(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_DEBUG_INIT "${CMAKE_C_FLAGS_DEBU_INITG}")
    STRING(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG_INIT "${CMAKE_CXX_FLAGS_DEBUG_INIT}")
    STRING(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${CMAKE_C_FLAGS_RELWITHDEBINFO_INIT}")
    STRING(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT}")
  ENDIF()
ENDIF()

SET(CMAKE_C_STANDARD 99)
SET(CMAKE_C_EXTENSIONS NO)
SET(CMAKE_CXX_STANDARD 14)
SET(CMAKE_CXX_STANDARD_REQUIRED YES)
SET(CMAKE_CXX_EXTENSIONS NO)

# ---[ Options.
SET(XNNPACK_LIBRARY_TYPE "default" CACHE STRING "Type of library (shared, static, or default) to build")
SET_PROPERTY(CACHE XNNPACK_LIBRARY_TYPE PROPERTY STRINGS default static shared)
IF(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
  # Disable assembly when using MSVC until support is added.
  OPTION(XNNPACK_ENABLE_ASSEMBLY "Build XNNPACK with assembly micro-kernels" OFF)
ELSE()
  OPTION(XNNPACK_ENABLE_ASSEMBLY "Build XNNPACK with assembly micro-kernels" ON)
ENDIF()
OPTION(XNNPACK_ENABLE_MEMOPT "Build XNNPACK with optimized memory allocation scheme" ON)
OPTION(XNNPACK_ENABLE_SPARSE "Build XNNPACK with graph rewriting for sparse inference" ON)
OPTION(XNNPACK_ENABLE_GEMM_M_SPECIALIZATION "Build XNNPACK with support for selecting microkernel with different MR" ON)
OPTION(XNNPACK_ENABLE_DWCONV_MULTIPASS "Build XNNPACK with DWCONV multipass microkernels enabled" OFF)
OPTION(XNNPACK_BUILD_LIBRARY "Build XNNPACK library" ON)
OPTION(XNNPACK_BUILD_TESTS "Build XNNPACK unit tests" ON)
OPTION(XNNPACK_BUILD_ALL_MICROKERNELS "Builds all XNNPACK Microkernels" ON)
OPTION(XNNPACK_BUILD_BENCHMARKS "Build XNNPACK benchmarks" ON)
OPTION(XNNPACK_BUILD_WITH_LIBM "Build XNNPACK with libm, can turn off on Windows to avoid mutiple math functions issue." ON)
OPTION(XNNPACK_USE_SYSTEM_LIBS "Use system-provided dependency libraries" OFF)
OPTION(USE_GNU_SOURCE "Use _GNU_SOURCE macro" OFF)
IF(XNNPACK_BUILD_BENCHMARKS OR XNNPACK_BUILD_TESTS)
  SET(XNNPACK_BUILD_ALL_MICROKERNELS ON)
ENDIF()

# --- [ Determine target processor
IF(CMAKE_OSX_ARCHITECTURES)
  LIST(LENGTH CMAKE_OSX_ARCHITECTURES CMAKE_OSX_ARCHITECTURES_COUNT)
  IF(CMAKE_OSX_ARCHITECTURES_COUNT GREATER 1)
    MESSAGE(FATAL_ERROR "Unsupported XNNPACK build with multiple OSX architectures (${CMAKE_OSX_ARCHITECTURES}). "
      "Specify a single architecture in CMAKE_OSX_ARCHITECTURES and re-configure. ")
  ENDIF()
  IF(NOT CMAKE_OSX_ARCHITECTURES MATCHES "^(x86_64|arm64|arm64e|arm64_32)$")
    MESSAGE(FATAL_ERROR "Unrecognized CMAKE_OSX_ARCHITECTURES value \"${CMAKE_OSX_ARCHITECTURES}\"")
  ENDIF()
  SET(XNNPACK_TARGET_PROCESSOR "${CMAKE_OSX_ARCHITECTURES}")
  ADD_COMPILE_OPTIONS("-Wno-shorten-64-to-32")
ELSEIF(CMAKE_GENERATOR MATCHES "^Visual Studio " AND CMAKE_GENERATOR_PLATFORM)
  IF(CMAKE_GENERATOR_PLATFORM STREQUAL "Win32")
    SET(XNNPACK_TARGET_PROCESSOR "x86")
  ELSEIF(CMAKE_GENERATOR_PLATFORM STREQUAL "x64")
    SET(XNNPACK_TARGET_PROCESSOR "x86_64")
  ELSEIF(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64")
    SET(XNNPACK_TARGET_PROCESSOR "arm64")
  ELSEIF(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64EC")
    SET(XNNPACK_TARGET_PROCESSOR "arm64")
  ELSE()
    MESSAGE(FATAL_ERROR "Unsupported Visual Studio architecture \"${CMAKE_GENERATOR_PLATFORM}\"")
  ENDIF()
ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^i[3-7]86$")
  SET(XNNPACK_TARGET_PROCESSOR "x86")
ELSEIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64")
  SET(XNNPACK_TARGET_PROCESSOR "x86_64")
ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^armv[5-8]")
  SET(XNNPACK_TARGET_PROCESSOR "arm")
ELSEIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
  SET(XNNPACK_TARGET_PROCESSOR "arm64")
ELSEIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le")
  SET(XNNPACK_TARGET_PROCESSOR "ppc64")
ELSEIF(NOT XNNPACK_TARGET_PROCESSOR MATCHES "^(x86(_64)?|arm64|riscv(32|64|128)|Hexagon|ppc64)$")
  SET(XNNPACK_TARGET_PROCESSOR "${CMAKE_SYSTEM_PROCESSOR}")
ELSE()
  MESSAGE(FATAL_ERROR "Unrecognized CMAKE_SYSTEM_PROCESSOR value \"${CMAKE_SYSTEM_PROCESSOR}\"")
ENDIF()
MESSAGE(STATUS "Building for XNNPACK_TARGET_PROCESSOR: ${XNNPACK_TARGET_PROCESSOR}")

# --- [ Processor-specific options
OPTION(XNNPACK_ENABLE_ARM_FP16_SCALAR "Build XNNPACK with ARM FP16 (FP16 data processing) scalar micro-kernels" ON)
OPTION(XNNPACK_ENABLE_ARM_FP16_VECTOR "Build XNNPACK with ARM FP16 (FP16 data processing) vector micro-kernels" ON)
OPTION(XNNPACK_ENABLE_ARM_BF16 "Build XNNPACK with ARM BF16 (BFLOAT16) micro-kernels" ON)
OPTION(XNNPACK_ENABLE_ARM_DOTPROD "Build XNNPACK with ARM DotProd (integer dot product) micro-kernels" ON)
OPTION(XNNPACK_ENABLE_ARM_I8MM "Build XNNPACK with ARM I8MM (8-bit integer matrix multiply accumulate) micro-kernels" ON)
OPTION(XNNPACK_ENABLE_ARM_SME "Build XNNPACK with ARM SME micro-kernels" ON)
OPTION(XNNPACK_ENABLE_ARM_SME2 "Build XNNPACK with ARM SME2 micro-kernels" ON)
IF(NOT XNNPACK_TARGET_PROCESSOR MATCHES "arm(64)?")
  SET(XNNPACK_ENABLE_ARM_FP16_SCALAR OFF)
  SET(XNNPACK_ENABLE_ARM_FP16_VECTOR OFF)
  SET(XNNPACK_ENABLE_ARM_BF16 OFF)
  SET(XNNPACK_ENABLE_ARM_DOTPROD OFF)
ENDIF()
IF(NOT XNNPACK_TARGET_PROCESSOR STREQUAL "arm64")
  SET(XNNPACK_ENABLE_ARM_I8MM OFF)
  SET(XNNPACK_ENABLE_ARM_SME OFF)
  SET(XNNPACK_ENABLE_ARM_SME2 OFF)
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "11")
  SET(XNNPACK_ENABLE_ARM_I8MM OFF)
  SET(XNNPACK_ENABLE_ARM_SME OFF)
  SET(XNNPACK_ENABLE_ARM_SME2 OFF)
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "18")
  SET(XNNPACK_ENABLE_ARM_SME OFF)
  SET(XNNPACK_ENABLE_ARM_SME2 OFF)
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "10")
  SET(XNNPACK_ENABLE_ARM_SME OFF)
  SET(XNNPACK_ENABLE_ARM_SME2 OFF)
ENDIF()
OPTION(XNNPACK_ENABLE_RISCV_VECTOR "Build XNNPACK with RISC-V Vector micro-kernels" ON)
OPTION(XNNPACK_ENABLE_VSX "Build XNNPACK with VSX Vector micro-kernels for Power" ON)
OPTION(XNNPACK_ENABLE_AVXVNNI "Build XNNPACK with AVX-VNNI micro-kernels" ON)
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "11")
    SET(XNNPACK_ENABLE_AVXVNNI OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "15")
    SET(XNNPACK_ENABLE_AVXVNNI OFF)
  ENDIF()
ENDIF()
OPTION(XNNPACK_ENABLE_AVXVNNIINT8 "Build XNNPACK with AVX-VNNI-INT8 micro-kernels" ON)
IF(CMAKE_SYSTEM_NAME MATCHES "^(Android|Darwin|iOS)$")
  SET(XNNPACK_ENABLE_AVXVNNIINT8 OFF)
ENDIF()
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "17")
    SET(XNNPACK_ENABLE_AVXVNNIINT8 OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "17")
    SET(XNNPACK_ENABLE_AVXVNNIINT8 OFF)
  ENDIF()
ENDIF()
OPTION(XNNPACK_ENABLE_AVX256SKX "Build XNNPACK with AVX256SKX micro-kernels" ON)
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "11")
    SET(XNNPACK_ENABLE_AVX256SKX OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "15")
    SET(XNNPACK_ENABLE_AVX256SKX OFF)
  ENDIF()
ENDIF()
OPTION(XNNPACK_ENABLE_AVX256VNNI "Build XNNPACK with AVX256VNNI micro-kernels" ON)
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "11")
    SET(XNNPACK_ENABLE_AVX256VNNI OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "15")
    SET(XNNPACK_ENABLE_AVX256VNNI OFF)
  ENDIF()
ENDIF()
OPTION(XNNPACK_ENABLE_AVX256VNNIGFNI "Build XNNPACK with AVX256VNNIGFNI micro-kernels" ON)
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "11")
    SET(XNNPACK_ENABLE_AVX256VNNIGFNI OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "15")
    SET(XNNPACK_ENABLE_AVX256VNNIGFNI OFF)
  ENDIF()
ENDIF()
OPTION(XNNPACK_ENABLE_AVX512F "Build XNNPACK with AVX512F micro-kernels" ON)
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "8")
    SET(XNNPACK_ENABLE_AVX512F OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "6")
    SET(XNNPACK_ENABLE_AVX512F OFF)
  ENDIF()
ENDIF()
OPTION(XNNPACK_ENABLE_AVX512SKX "Build XNNPACK with AVX512SKX micro-kernels" ON)
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "8")
    SET(XNNPACK_ENABLE_AVX512SKX OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "6")
    SET(XNNPACK_ENABLE_AVX512SKX OFF)
  ENDIF()
ENDIF()
OPTION(XNNPACK_ENABLE_AVX512VBMI "Build XNNPACK with AVX512VBMI micro-kernels" ON)
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "8")
    SET(XNNPACK_ENABLE_AVX512VBMI OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "6")
    SET(XNNPACK_ENABLE_AVX512VBMI OFF)
  ENDIF()
ENDIF()
OPTION(XNNPACK_ENABLE_AVX512VNNI "Build XNNPACK with AVX512VNNI micro-kernels" ON)
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "8")
    SET(XNNPACK_ENABLE_AVX512VNNI OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "6")
    SET(XNNPACK_ENABLE_AVX512VNNI OFF)
  ENDIF()
ENDIF()
OPTION(XNNPACK_ENABLE_AVX512VNNIGFNI "Build XNNPACK with AVX512VNNIGFNI micro-kernels" ON)
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "8")
    SET(XNNPACK_ENABLE_AVX512VNNIGFNI OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "6")
    SET(XNNPACK_ENABLE_AVX512VNNIGFNI OFF)
  ENDIF()
ENDIF()
OPTION(XNNPACK_ENABLE_AVX512AMX "Build XNNPACK with AVX512-AMX micro-kernels" ON)
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "13")
    SET(XNNPACK_ENABLE_AVX512AMX OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "15")
    SET(XNNPACK_ENABLE_AVX512AMX OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
  SET(XNNPACK_ENABLE_AVX512AMX OFF)
ENDIF()
IF(XNNPACK_TARGET_PROCESSOR STREQUAL "x86")
  SET(XNNPACK_ENABLE_AVX512AMX OFF)
ENDIF()
OPTION(XNNPACK_ENABLE_AVX512FP16 "Build XNNPACK with AVX512-FP16 micro-kernels" ON)
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "13")
    SET(XNNPACK_ENABLE_AVX512FP16 OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "15")
    SET(XNNPACK_ENABLE_AVX512FP16 OFF)
  ENDIF()
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
  SET(XNNPACK_ENABLE_AVX512FP16 OFF)
ENDIF()
OPTION(XNNPACK_ENABLE_HVX "Build XNNPACK with Hexagon HVX micro-kernels" ON)
OPTION(XNNPACK_ENABLE_KLEIDIAI "Use KleidiAI GEMM microkernels for Arm" ON)
IF(XNNPACK_TARGET_PROCESSOR STREQUAL "arm64" AND XNNPACK_ENABLE_ARM_I8MM AND NOT CMAKE_C_COMPILER_ID STREQUAL "MSVC")
  IF (XNNPACK_ENABLE_KLEIDIAI)
    MESSAGE(STATUS "Enabling KleidiAI for Arm64")
  ENDIF()
ELSE()
  SET(XNNPACK_ENABLE_KLEIDIAI OFF)
ENDIF()

# ---[ CMake options
INCLUDE(GNUInstallDirs)

IF(XNNPACK_BUILD_TESTS)
  ENABLE_TESTING()
ENDIF()

ADD_COMPILE_DEFINITIONS("XNN_ENABLE_ARM_FP16_VECTOR=$<BOOL:${XNNPACK_ENABLE_ARM_FP16_VECTOR}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_ARM_FP16_SCALAR=$<BOOL:${XNNPACK_ENABLE_ARM_FP16_SCALAR}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_ARM_BF16=$<BOOL:${XNNPACK_ENABLE_ARM_BF16}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_ARM_DOTPROD=$<BOOL:${XNNPACK_ENABLE_ARM_DOTPROD}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_ARM_I8MM=$<BOOL:${XNNPACK_ENABLE_ARM_I8MM}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_ARM_SME=$<BOOL:${XNNPACK_ENABLE_ARM_SME}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_ARM_SME2=$<BOOL:${XNNPACK_ENABLE_ARM_SME2}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_RISCV_VECTOR=$<BOOL:${XNNPACK_ENABLE_RISCV_VECTOR}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_AVXVNNI=$<BOOL:${XNNPACK_ENABLE_AVXVNNI}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_AVXVNNIINT8=$<BOOL:${XNNPACK_ENABLE_AVXVNNIINT8}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_AVX256SKX=$<BOOL:${XNNPACK_ENABLE_AVX256SKX}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_AVX256VNNI=$<BOOL:${XNNPACK_ENABLE_AVX256VNNI}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_AVX256VNNIGFNI=$<BOOL:${XNNPACK_ENABLE_AVX256VNNIGFNI}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_AVX512F=$<BOOL:${XNNPACK_ENABLE_AVX512F}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_AVX512SKX=$<BOOL:${XNNPACK_ENABLE_AVX512SKX}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_AVX512VBMI=$<BOOL:${XNNPACK_ENABLE_AVX512VBMI}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_AVX512VNNI=$<BOOL:${XNNPACK_ENABLE_AVX512VNNI}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_AVX512VNNIGFNI=$<BOOL:${XNNPACK_ENABLE_AVX512VNNIGFNI}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_AVX512AMX=$<BOOL:${XNNPACK_ENABLE_AVX512AMX}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_AVX512FP16=$<BOOL:${XNNPACK_ENABLE_AVX512FP16}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_VSX=$<BOOL:${XNNPACK_ENABLE_VSX}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_ASSEMBLY=$<BOOL:${XNNPACK_ENABLE_ASSEMBLY}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_MEMOPT=$<BOOL:${XNNPACK_ENABLE_MEMOPT}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_SPARSE=$<BOOL:${XNNPACK_ENABLE_SPARSE}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_GEMM_M_SPECIALIZATION=$<BOOL:${XNNPACK_ENABLE_GEMM_M_SPECIALIZATION}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_DWCONV_MULTIPASS=$<BOOL:${XNNPACK_ENABLE_DWCONV_MULTIPASS}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_HVX=$<BOOL:${XNNPACK_ENABLE_HVX}>")
ADD_COMPILE_DEFINITIONS("XNN_ENABLE_KLEIDIAI=$<BOOL:${XNNPACK_ENABLE_KLEIDIAI}>")

IF(XNNPACK_TARGET_PROCESSOR MATCHES "Hexagon")
  ADD_COMPILE_DEFINITIONS("XNN_ENABLE_CPUINFO=0")
ELSE()
  ADD_COMPILE_DEFINITIONS("XNN_ENABLE_CPUINFO=1")
ENDIF()

IF(USE_GNU_SOURCE)
  ADD_COMPILE_DEFINITIONS(_GNU_SOURCE)
ENDIF()

IF(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
  # Disable "unary minus operator applied to unsigned type, result still unsigned" warning
  ADD_COMPILE_OPTIONS("/wd4146")
  # Test files have many sections, increase the limit. See
  # https://learn.microsoft.com/en-us/cpp/build/reference/bigobj-increase-number-of-sections-in-dot-obj-file.
  ADD_COMPILE_OPTIONS("/bigobj")
ENDIF()

IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
  # Disable "note: parameter passing for argument of type ... changed/will change in ..."
  ADD_COMPILE_OPTIONS("-Wno-psabi")
ENDIF()

# ---[ Build flags
IF(NOT CMAKE_SYSTEM_NAME)
  MESSAGE(FATAL_ERROR "CMAKE_SYSTEM_NAME not defined")
ELSEIF(NOT CMAKE_SYSTEM_NAME MATCHES "^(Android|Darwin|iOS|Linux|Windows|CYGWIN|MSYS|QURT)$")
  MESSAGE(FATAL_ERROR "Unrecognized CMAKE_SYSTEM_NAME value \"${CMAKE_SYSTEM_NAME}\"")
ENDIF()
IF(CMAKE_SYSTEM_NAME MATCHES "Windows")
  # Disable min/max macros as they break std::min/max and std::numeric_limits<T>min/max.
  ADD_COMPILE_DEFINITIONS("NOMINMAX")
ENDIF()

# ---[ Download deps
IF(NOT XNNPACK_USE_SYSTEM_LIBS)
  IF(NOT DEFINED CPUINFO_SOURCE_DIR)
    MESSAGE(STATUS "Downloading cpuinfo to ${CMAKE_BINARY_DIR}/cpuinfo-source (define CPUINFO_SOURCE_DIR to avoid it)")
    CONFIGURE_FILE(cmake/DownloadCpuinfo.cmake "${CMAKE_BINARY_DIR}/cpuinfo-download/CMakeLists.txt")
    EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/cpuinfo-download")
    EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" --build .
      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/cpuinfo-download")
    SET(CPUINFO_SOURCE_DIR "${CMAKE_BINARY_DIR}/cpuinfo-source" CACHE STRING "cpuinfo source directory")
  ENDIF()

  IF(NOT DEFINED FXDIV_SOURCE_DIR)
    MESSAGE(STATUS "Downloading FXdiv to ${CMAKE_BINARY_DIR}/FXdiv-source (define FXDIV_SOURCE_DIR to avoid it)")
    CONFIGURE_FILE(cmake/DownloadFXdiv.cmake "${CMAKE_BINARY_DIR}/FXdiv-download/CMakeLists.txt")
    EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/FXdiv-download")
    EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" --build .
      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/FXdiv-download")
    SET(FXDIV_SOURCE_DIR "${CMAKE_BINARY_DIR}/FXdiv-source" CACHE STRING "FXdiv source directory")
  ENDIF()

  IF(NOT DEFINED PTHREADPOOL_SOURCE_DIR)
    MESSAGE(STATUS "Downloading pthreadpool to ${CMAKE_BINARY_DIR}/pthreadpool-source (define PTHREADPOOL_SOURCE_DIR to avoid it)")
    CONFIGURE_FILE(cmake/DownloadPThreadPool.cmake "${CMAKE_BINARY_DIR}/pthreadpool-download/CMakeLists.txt")
    EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/pthreadpool-download")
    EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" --build .
      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/pthreadpool-download")
    SET(PTHREADPOOL_SOURCE_DIR "${CMAKE_BINARY_DIR}/pthreadpool-source" CACHE STRING "pthreadpool source directory")
  ENDIF()

  IF(XNNPACK_BUILD_TESTS AND NOT DEFINED GOOGLETEST_SOURCE_DIR)
    MESSAGE(STATUS "Downloading Google Test to ${CMAKE_BINARY_DIR}/googletest-source (define GOOGLETEST_SOURCE_DIR to avoid it)")
    CONFIGURE_FILE(cmake/DownloadGoogleTest.cmake "${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt")
    EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/googletest-download")
    EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" --build .
      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/googletest-download")
    SET(GOOGLETEST_SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-source" CACHE STRING "Google Test source directory")
  ENDIF()

  IF(XNNPACK_BUILD_BENCHMARKS AND NOT DEFINED GOOGLEBENCHMARK_SOURCE_DIR)
    MESSAGE(STATUS "Downloading Google Benchmark to ${CMAKE_BINARY_DIR}/googlebenchmark-source (define GOOGLEBENCHMARK_SOURCE_DIR to avoid it)")
    CONFIGURE_FILE(cmake/DownloadGoogleBenchmark.cmake "${CMAKE_BINARY_DIR}/googlebenchmark-download/CMakeLists.txt")
    EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/googlebenchmark-download")
    EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" --build .
      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/googlebenchmark-download")
    SET(GOOGLEBENCHMARK_SOURCE_DIR "${CMAKE_BINARY_DIR}/googlebenchmark-source" CACHE STRING "Google Benchmark source directory")
  ENDIF()

  IF(XNNPACK_ENABLE_KLEIDIAI AND NOT DEFINED KLEIDIAI_SOURCE_DIR)
    MESSAGE(STATUS "Downloading KleidiAI to ${CMAKE_BINARY_DIR}/kleidiai-source (define KLEIDIAI_SOURCE_DIR to avoid it)")
    CONFIGURE_FILE(cmake/DownloadKleidiAI.cmake "${CMAKE_BINARY_DIR}/kleidiai-download/CMakeLists.txt")
    EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/kleidiai-download")
    EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" --build .
      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/kleidiai-download")
    SET(KLEIDIAI_SOURCE_DIR "${CMAKE_BINARY_DIR}/kleidiai-source" CACHE STRING "kleidiai source directory")
  ENDIF()
ENDIF()

# ---[ XNNPACK library

IF (NOT DEFINED Python_EXECUTABLE)
  find_package(Python COMPONENTS Interpreter)

  IF(NOT Python_FOUND)
    SET(PYTHON_EXECUTABLE "python3")
  ENDIF()
ENDIF()

# Generate and load the micorkernels.cmake files.
MESSAGE(STATUS "Generating microkernels.cmake")
EXECUTE_PROCESS(
  COMMAND "${Python_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/tools/update-microkernels.py" --output "${PROJECT_BINARY_DIR}"
  RESULT_VARIABLE UPDATE_MICROKERNELS_RESULT
)
IF(NOT UPDATE_MICROKERNELS_RESULT EQUAL 0)
  MESSAGE(FATAL_ERROR "Failed to generate \"microkernels.cmake\".")
ENDIF()
INCLUDE("${PROJECT_BINARY_DIR}/cmake/gen/microkernels.cmake")

SET(OPERATOR_SRCS
  src/operator-delete.c
  src/operators/argmax-pooling-nhwc.c
  src/operators/average-pooling-nhwc.c
  src/operators/batch-matrix-multiply-nc.c
  src/operators/binary-elementwise-nd.c
  src/operators/constant-pad-nd.c
  src/operators/convolution-nchw.c
  src/operators/convolution-nhwc.c
  src/operators/deconvolution-nhwc.c
  src/operators/dynamic-fully-connected-nc.c
  src/operators/fully-connected-nc.c
  src/operators/max-pooling-nhwc.c
  src/operators/pack-lh.c
  src/operators/reduce-nd.c
  src/operators/resize-bilinear-nchw.c
  src/operators/resize-bilinear-nhwc.c
  src/operators/rope-nthc.c
  src/operators/scaled-dot-product-attention-nhtc.c
  src/operators/slice-nd.c
  src/operators/softmax-nc.c
  src/operators/transpose-nd.c
  src/operators/unary-elementwise-nc.c
  src/operators/unpooling-nhwc.c)

SET(REFERENCE_SRCS
  src/reference/unary-elementwise.cc
  src/reference/binary-elementwise.cc)

SET(SUBGRAPH_SRCS
  src/memory-planner.c
  src/runtime.c
  src/subgraph.c
  src/subgraph/argmax-pooling-2d.c
  src/subgraph/average-pooling-2d.c
  src/subgraph/batch-matrix-multiply.c
  src/subgraph/binary.c
  src/subgraph/concatenate.c
  src/subgraph/convolution-2d.c
  src/subgraph/copy.c
  src/subgraph/deconvolution-2d.c
  src/subgraph/deprecated.c
  src/subgraph/depth-to-space-2d.c
  src/subgraph/depthwise-convolution-2d.c
  src/subgraph/even-split.c
  src/subgraph/fully-connected-sparse.c
  src/subgraph/fully-connected.c
  src/subgraph/max-pooling-2d.c
  src/subgraph/pack-lh.c
  src/subgraph/reshape-helpers.c
  src/subgraph/scaled-dot-product-attention.c
  src/subgraph/softmax.c
  src/subgraph/space-to-depth-2d.c
  src/subgraph/static-constant-pad.c
  src/subgraph/static-reduce.c
  src/subgraph/static-resize-bilinear-2d.c
  src/subgraph/static-slice.c
  src/subgraph/static-transpose.c
  src/subgraph/unpooling-2d.c
  src/subgraph/unary.c
  src/subgraph/validation.c
  src/tensor.c)

SET(LOGGING_SRCS
  src/enums/allocation-type.c
  src/enums/datatype-strings.c
  src/enums/microkernel-type.c
  src/enums/node-type.c
  src/enums/operator-type.c
  src/log.c)

SET(XNNPACK_SRCS
  src/configs/argmaxpool-config.c
  src/configs/avgpool-config.c
  src/configs/binary-elementwise-config.c
  src/configs/cmul-config.c
  src/configs/conv-hwc2chw-config.c
  src/configs/dwconv-config.c
  src/configs/dwconv2d-chw-config.c
  src/configs/experiments-config.c
  src/configs/gemm-config.c
  src/configs/ibilinear-chw-config.c
  src/configs/ibilinear-config.c
  src/configs/lut32norm-config.c
  src/configs/maxpool-config.c
  src/configs/pavgpool-config.c
  src/configs/pack-lh-config.c
  src/configs/raddstoreexpminusmax-config.c
  src/configs/reduce-config.c
  src/configs/rmax-config.c
  src/configs/spmm-config.c
  src/configs/transpose-config.c
  src/configs/unary-elementwise-config.c
  src/configs/unpool-config.c
  src/configs/vmulcaddc-config.c
  src/configs/xx-fill-config.c
  src/configs/xx-pad-config.c
  src/configs/x8-lut-config.c
  src/init.c
  src/params.c
  "${PROJECT_BINARY_DIR}/build_identifier.c")

SET(TABLE_SRCS
  src/tables/exp2-k-over-64.c
  src/tables/exp2-k-over-2048.c
  src/tables/exp2minus-k-over-4.c
  src/tables/exp2minus-k-over-8.c
  src/tables/exp2minus-k-over-16.c
  src/tables/exp2minus-k-over-32.c
  src/tables/exp2minus-k-over-64.c
  src/tables/exp2minus-k-over-2048.c
  src/tables/vlog.c)

SET(PROD_MICROKERNEL_SRCS ${PROD_SCALAR_MICROKERNEL_SRCS})
SET(NON_PROD_MICROKERNEL_SRCS ${NON_PROD_SCALAR_MICROKERNEL_SRCS})
IF(XNNPACK_TARGET_PROCESSOR STREQUAL "arm")
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_ARMSIMD32_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEON_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONFP16_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONFMA_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONV8_MICROKERNEL_SRCS})
  IF(XNNPACK_ENABLE_ARM_FP16_SCALAR)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_FP16ARITH_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_FP16_VECTOR)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONFP16ARITH_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_DOTPROD)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONDOT_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_DOTPROD AND XNNPACK_ENABLE_ARM_FP16_VECTOR)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONDOTFP16ARITH_MICROKERNEL_SRCS})
  ENDIF()
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_ARMSIMD32_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEON_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONFP16_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONFMA_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONV8_MICROKERNEL_SRCS})
  IF(XNNPACK_ENABLE_ARM_FP16_SCALAR)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_FP16ARITH_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_FP16_VECTOR AND XNNPACK_ENABLE_ARM_DOTPROD)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONDOTFP16ARITH_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_FP16_VECTOR)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONFP16ARITH_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_BF16)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONBF16_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_DOTPROD)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONDOT_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ASSEMBLY)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AARCH32_ASM_MICROKERNEL_SRCS})
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AARCH32_ASM_MICROKERNEL_SRCS})
  ENDIF()
ENDIF()
IF(XNNPACK_TARGET_PROCESSOR MATCHES "^arm64")
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEON_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONFP16_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONFMA_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONV8_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEON_AARCH64_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONFMA_AARCH64_MICROKERNEL_SRCS})
  IF(XNNPACK_ENABLE_ARM_FP16_SCALAR)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_FP16ARITH_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_FP16_VECTOR)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONFP16ARITH_MICROKERNEL_SRCS})
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONFP16ARITH_AARCH64_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_DOTPROD)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONDOT_MICROKERNEL_SRCS})
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONDOT_AARCH64_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_DOTPROD AND XNNPACK_ENABLE_ARM_FP16_VECTOR)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONDOTFP16ARITH_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_I8MM)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONI8MM_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_SME)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONSME_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_SME2)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_NEONSME2_MICROKERNEL_SRCS})
  ENDIF()
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEON_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONFP16_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONFMA_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONV8_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEON_AARCH64_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONFMA_AARCH64_MICROKERNEL_SRCS})
  IF(XNNPACK_ENABLE_ARM_FP16_SCALAR)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_FP16ARITH_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_FP16_VECTOR AND XNNPACK_ENABLE_ARM_DOTPROD)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONDOTFP16ARITH_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_FP16_VECTOR)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONFP16ARITH_MICROKERNEL_SRCS})
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONFP16ARITH_AARCH64_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_BF16)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONBF16_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_DOTPROD)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONDOT_MICROKERNEL_SRCS})
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONDOT_AARCH64_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_I8MM)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONI8MM_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_SME)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONSME_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ARM_SME2)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_NEONSME2_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_ASSEMBLY)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AARCH64_ASM_MICROKERNEL_SRCS})
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AARCH64_ASM_MICROKERNEL_SRCS})
  ENDIF()
ENDIF()
IF(XNNPACK_TARGET_PROCESSOR MATCHES "^x86(_64)?$")
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_SSE_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_SSE2_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_SSSE3_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_SSE41_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_F16C_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_FMA3_MICROKERNEL_SRCS})
  LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX2_MICROKERNEL_SRCS})
  IF(XNNPACK_ENABLE_ASSEMBLY AND XNNPACK_TARGET_PROCESSOR MATCHES "x86_64")
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AMD64_ASM_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512AMX)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX512AMX_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512FP16)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX512FP16_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVXVNNI)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVXVNNI_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVXVNNIINT8)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVXVNNIINT8_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX256SKX)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX256SKX_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX256VNNI)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX256VNNI_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX256VNNIGFNI)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX256VNNIGFNI_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512F)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX512F_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512SKX)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX512SKX_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512VBMI)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX512VBMI_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512VNNI)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX512VNNI_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512VNNIGFNI)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX512VNNIGFNI_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512VNNIGFNI)
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_AVX512VNNIGFNI_MICROKERNEL_SRCS})
  ENDIF()
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_SSE_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_SSE2_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_SSSE3_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_SSE41_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVX_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_F16C_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_FMA3_MICROKERNEL_SRCS})
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVX2_MICROKERNEL_SRCS})
  IF(XNNPACK_ENABLE_ASSEMBLY AND XNNPACK_TARGET_PROCESSOR MATCHES "x86_64")
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AMD64_ASM_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512AMX)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVX512AMX_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512FP16)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVX512FP16_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVXVNNI)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVXVNNI_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVXVNNIINT8)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVXVNNIINT8_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX256SKX)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVX256SKX_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX256VNNI)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVX256VNNI_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX256VNNIGFNI)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVX256VNNIGFNI_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512F)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVX512F_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512SKX)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVX512SKX_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512VBMI)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVX512VBMI_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512VNNI)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVX512VNNI_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_AVX512VNNIGFNI)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_AVX512VNNIGFNI_MICROKERNEL_SRCS})
  ENDIF()
ENDIF()
IF(XNNPACK_TARGET_PROCESSOR MATCHES "Hexagon")
  LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_HEXAGON_MICROKERNEL_SRCS})
  IF(XNNPACK_ENABLE_HVX)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_HVX_MICROKERNEL_SRCS})
  ENDIF()
ENDIF()
IF(XNNPACK_TARGET_PROCESSOR MATCHES "^ppc64")
  IF(XNNPACK_ENABLE_VSX)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_PPC64_MICROKERNEL_SRCS})
  ENDIF()
ENDIF()
IF(XNNPACK_TARGET_PROCESSOR MATCHES "^riscv")
  LIST(APPEND PROD_MICROKERNEL_SRCS)
  IF(XNNPACK_ENABLE_RISCV_VECTOR)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_RVV_MICROKERNEL_SRCS})
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_RVV_MICROKERNEL_SRCS})
  ENDIF()
  IF(XNNPACK_ENABLE_RISCV_FP16_VECTOR)
    LIST(APPEND NON_PROD_MICROKERNEL_SRCS ${NON_PROD_RVVFP16ARITH_MICROKERNEL_SRCS})
    LIST(APPEND PROD_MICROKERNEL_SRCS ${PROD_RVVFP16ARITH_MICROKERNEL_SRCS})
  ENDIF()
ENDIF()

SET(ALL_MICROKERNEL_SRCS ${PROD_MICROKERNEL_SRCS} ${NON_PROD_MICROKERNEL_SRCS})

LIST(SORT PROD_MICROKERNEL_SRCS)
STRING(REPLACE ";" "\n" PROD_MICROKERNEL_SRCS_WITH_NEWLINES "${PROD_MICROKERNEL_SRCS}")
FILE(GENERATE OUTPUT "${PROJECT_BINARY_DIR}/prod_microkernel_srcs.txt" CONTENT "${PROD_MICROKERNEL_SRCS_WITH_NEWLINES}")
ADD_CUSTOM_COMMAND(
  OUTPUT "${PROJECT_BINARY_DIR}/build_identifier.c"
  COMMAND "${Python_EXECUTABLE}" "scripts/generate-build-identifier.py" --output "${PROJECT_BINARY_DIR}/build_identifier.c" --input_file_list "${PROJECT_BINARY_DIR}/prod_microkernel_srcs.txt"
  DEPENDS "${PROJECT_BINARY_DIR}/prod_microkernel_srcs.txt"
  WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
)

# Create a dummy library that contains shared dependencies and definitions for
# all other XNNPACK targets.
ADD_LIBRARY(xnnpack-base INTERFACE)

ADD_LIBRARY(microkernels-prod STATIC ${PROD_MICROKERNEL_SRCS} ${TABLE_SRCS})
IF(XNNPACK_BUILD_ALL_MICROKERNELS)
  ADD_LIBRARY(microkernels-all STATIC ${NON_PROD_MICROKERNEL_SRCS})
  TARGET_LINK_LIBRARIES(microkernels-all PUBLIC microkernels-prod)
ENDIF()
ADD_LIBRARY(hardware-config OBJECT src/configs/hardware-config.c)
ADD_LIBRARY(indirection OBJECT src/indirection.c)
ADD_LIBRARY(logging OBJECT ${LOGGING_SRCS})
ADD_LIBRARY(microparams-init OBJECT src/microparams-init.c)
ADD_LIBRARY(normalization OBJECT src/normalization.c)
ADD_LIBRARY(packing OBJECT src/reference/packing.cc)
TARGET_LINK_LIBRARIES(hardware-config PRIVATE xnnpack-base logging)
TARGET_LINK_LIBRARIES(indirection PRIVATE xnnpack-base)
TARGET_LINK_LIBRARIES(logging PRIVATE xnnpack-base)
IF(XNNPACK_BUILD_ALL_MICROKERNELS)
  TARGET_LINK_LIBRARIES(microkernels-all PRIVATE xnnpack-base)
ENDIF()
TARGET_LINK_LIBRARIES(microkernels-prod PRIVATE xnnpack-base)
TARGET_LINK_LIBRARIES(microparams-init PRIVATE xnnpack-base)
TARGET_LINK_LIBRARIES(normalization PRIVATE xnnpack-base)
TARGET_LINK_LIBRARIES(packing PRIVATE xnnpack-base logging)
IF(XNNPACK_BUILD_LIBRARY)
  ADD_LIBRARY(allocator OBJECT src/allocator.c)
  ADD_LIBRARY(cache OBJECT src/cache.c)
  ADD_LIBRARY(datatype OBJECT src/datatype.c)
  ADD_LIBRARY(memory OBJECT src/memory.c)
  ADD_LIBRARY(microkernel-utils OBJECT src/microkernel-utils.c)
  ADD_LIBRARY(mutex OBJECT src/mutex.c)
  ADD_LIBRARY(operators OBJECT ${OPERATOR_SRCS})
  ADD_LIBRARY(operator-run OBJECT src/operator-run.c)
  ADD_LIBRARY(operator-utils OBJECT src/operator-utils.c)
  ADD_LIBRARY(reference-ukernels OBJECT ${REFERENCE_SRCS})
  ADD_LIBRARY(subgraph OBJECT ${SUBGRAPH_SRCS})
  # Need C_EXTENSIONS to get constants for mmap (MAP_ANONYMOUS).
  SET_TARGET_PROPERTIES(memory PROPERTIES C_EXTENSIONS YES)
  IF(XNNPACK_LIBRARY_TYPE STREQUAL "default")
    ADD_LIBRARY(XNNPACK ${XNNPACK_SRCS})
  ELSEIF(XNNPACK_LIBRARY_TYPE STREQUAL "shared")
    ADD_LIBRARY(XNNPACK SHARED ${XNNPACK_SRCS})
  ELSEIF(XNNPACK_LIBRARY_TYPE STREQUAL "static")
    ADD_LIBRARY(XNNPACK STATIC ${XNNPACK_SRCS})
  ELSE()
    MESSAGE(FATAL_ERROR "Unsupported XNNPACK library type \"${XNNPACK_LIBRARY_TYPE}\". Must be \"static\", \"shared\", or \"default\"")
  ENDIF()

  TARGET_LINK_LIBRARIES(allocator PRIVATE xnnpack-base logging)
  TARGET_LINK_LIBRARIES(cache PRIVATE xnnpack-base logging)
  TARGET_LINK_LIBRARIES(datatype PRIVATE xnnpack-base)
  TARGET_LINK_LIBRARIES(memory PRIVATE xnnpack-base logging)
  TARGET_LINK_LIBRARIES(microkernel-utils PRIVATE xnnpack-base hardware-config logging)
  TARGET_LINK_LIBRARIES(mutex PRIVATE xnnpack-base logging)
  TARGET_LINK_LIBRARIES(operators PRIVATE xnnpack-base allocator indirection logging microkernel-utils normalization operator-utils packing reference-ukernels datatype)
  TARGET_LINK_LIBRARIES(operator-run PRIVATE xnnpack-base logging)
  TARGET_LINK_LIBRARIES(operator-utils PRIVATE xnnpack-base logging)
  TARGET_LINK_LIBRARIES(reference-ukernels PRIVATE xnnpack-base)
  TARGET_LINK_LIBRARIES(subgraph PRIVATE xnnpack-base allocator logging memory mutex operators operator-run datatype)
  TARGET_LINK_LIBRARIES(XNNPACK PRIVATE xnnpack-base allocator cache hardware-config indirection memory microkernel-utils microparams-init mutex normalization operators operator-run operator-utils packing microkernels-prod subgraph datatype reference-ukernels)
  TARGET_LINK_LIBRARIES(XNNPACK PUBLIC pthreadpool logging)
  SET_TARGET_PROPERTIES(XNNPACK PROPERTIES C_EXTENSIONS YES)
ENDIF()
IF(NOT MSVC)
  SET_PROPERTY(SOURCE ${ALL_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-math-errno ")
ENDIF()
IF(XNNPACK_TARGET_PROCESSOR STREQUAL "arm")
  SET_PROPERTY(SOURCE ${ALL_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -marm ")
  SET_PROPERTY(SOURCE ${ALL_ARMSIMD32_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv6 -mfpu=vfp -munaligned-access ")
  SET_PROPERTY(SOURCE ${ALL_NEON_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv7-a -mfpu=neon ")
  SET_PROPERTY(SOURCE ${ALL_NEONFP16_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv7-a -mfpu=neon-fp16 ")
  # GCC requires -mfp16-format=ieee to define __fp16 type, but Clang doesn't support this option at all.
  IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
    SET_PROPERTY(SOURCE ${ALL_NEONFP16_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mfp16-format=ieee ")
    SET_PROPERTY(SOURCE ${ALL_FP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mfp16-format=ieee ")
    SET_PROPERTY(SOURCE ${ALL_NEONDOTFP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mfp16-format=ieee ")
    SET_PROPERTY(SOURCE ${ALL_NEONFP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mfp16-format=ieee ")
  ENDIF()
  SET_PROPERTY(SOURCE ${ALL_NEONFMA_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv7-a -mfpu=neon-vfpv4 ")
  SET_PROPERTY(SOURCE ${ALL_NEONV8_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8-a -mfpu=neon-fp-armv8 ")
  # -mfpu=fp-armv8 should suffice for FP16ARITH microkernels, if not for GCC emitting wrong directives for assembler
  # -fno-math-errno for the vsqrth_f16 polyfill using sqrtf
  # -ffinite-math-only for the vminnmh_f16/vmaxnmh_f16 polyfills using compare + select
  SET_PROPERTY(SOURCE ${ALL_FP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+fp16 -mfpu=neon-fp-armv8 -fno-math-errno -ffinite-math-only ")
  SET_PROPERTY(SOURCE ${ALL_NEONDOTFP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+dotprod+fp16 -mfpu=neon-fp-armv8 -fno-math-errno -ffinite-math-only ")
  SET_PROPERTY(SOURCE ${ALL_NEONFP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+fp16 -mfpu=neon-fp-armv8 ")
  SET_PROPERTY(SOURCE ${ALL_NEONBF16_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+bf16 -mfpu=neon-fp-armv8 ")
  SET_PROPERTY(SOURCE ${ALL_NEONDOT_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+dotprod -mfpu=neon-fp-armv8 ")
  SET_PROPERTY(SOURCE ${ALL_AARCH32_ASM_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+dotprod+fp16 -mfpu=neon-fp-armv8 ")
  # Workground the neon detection bug in ARM v8
  # Related links:
  #   https://github.com/android/ndk/issues/910
  #   https://reviews.llvm.org/D58477
  IF(ANDROID_NDK_MAJOR AND ANDROID_NDK_MAJOR LESS 21)
    SET_PROPERTY(SOURCE ${ALL_NEONV8_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mfloat-abi=softfp ")
    SET_PROPERTY(SOURCE ${ALL_FP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mfloat-abi=softfp ")
    SET_PROPERTY(SOURCE ${ALL_NEONDOTFP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mfloat-abi=softfp ")
    SET_PROPERTY(SOURCE ${ALL_NEONFP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mfloat-abi=softfp ")
    SET_PROPERTY(SOURCE ${ALL_NEONBF16_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mfloat-abi=softfp ")
    SET_PROPERTY(SOURCE ${ALL_NEONDOT_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mfloat-abi=softfp ")
    SET_PROPERTY(SOURCE ${ALL_AARCH32_ASM_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mfloat-abi=softfp ")
  ENDIF()
ENDIF()
IF(XNNPACK_TARGET_PROCESSOR MATCHES "^arm64" AND NOT MSVC)
  SET_PROPERTY(SOURCE ${ALL_FP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+fp16 ")
  SET_PROPERTY(SOURCE ${ALL_NEONFP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+fp16 ")
  SET_PROPERTY(SOURCE ${ALL_NEONDOTFP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+dotprod+fp16 ")
  SET_PROPERTY(SOURCE ${ALL_NEONFP16ARITH_AARCH64_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+fp16 ")
  SET_PROPERTY(SOURCE ${ALL_NEONBF16_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+bf16 ")
  SET_PROPERTY(SOURCE ${ALL_NEONDOT_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+dotprod ")
  SET_PROPERTY(SOURCE ${ALL_NEONDOT_AARCH64_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+dotprod ")
  SET_PROPERTY(SOURCE ${ALL_NEONI8MM_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+i8mm+fp16 ")
  SET_PROPERTY(SOURCE ${ALL_NEONSME_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+sve+sve2 ")
  SET_PROPERTY(SOURCE ${ALL_NEONSME2_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+sve+sve2 ")
  SET_PROPERTY(SOURCE ${ALL_AARCH64_ASM_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=armv8.2-a+fp16+dotprod ")
ENDIF()
IF(XNNPACK_TARGET_PROCESSOR MATCHES "^ppc64")
  IF(XNNPACK_ENABLE_VSX)
    SET_PROPERTY(SOURCE ${ALL_PPC_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mvsx ")
  ENDIF()
ENDIF()
IF(XNNPACK_TARGET_PROCESSOR MATCHES "^riscv")
  IF(XNNPACK_ENABLE_RISCV_VECTOR)
    SET_PROPERTY(SOURCE ${ALL_RVV_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=rv64gcv -mabi=lp64d ")
  ENDIF()
  SET_PROPERTY(SOURCE ${ALL_RVVFP16ARITH_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -march=rv64gc_zvfh -mabi=lp64d ")
ENDIF()
IF(XNNPACK_TARGET_PROCESSOR MATCHES "^x86(_64)?$")
  IF(MSVC)
    IF(XNNPACK_TARGET_PROCESSOR STREQUAL "x86" OR CMAKE_SIZEOF_VOID_P EQUAL 4)
      SET_PROPERTY(SOURCE ${ALL_SSE_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:SSE ")
      SET_PROPERTY(SOURCE ${ALL_SSE2_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:SSE2 ")
      SET_PROPERTY(SOURCE ${ALL_SSSE3_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:SSE2 ")
      SET_PROPERTY(SOURCE ${ALL_SSE41_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:SSE2 ")
    ENDIF()
    SET_PROPERTY(SOURCE ${ALL_AVX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX ")
    SET_PROPERTY(SOURCE ${ALL_F16C_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX ")
    SET_PROPERTY(SOURCE ${ALL_FMA3_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX ")
    SET_PROPERTY(SOURCE ${ALL_AVX2_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX2 ")
    SET_PROPERTY(SOURCE ${ALL_AVX512F_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX512 ")
    SET_PROPERTY(SOURCE ${ALL_AVX512SKX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX512 ")
    SET_PROPERTY(SOURCE ${ALL_AVX512VBMI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX512 ")
    SET_PROPERTY(SOURCE ${ALL_AVX512VNNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX512 ")
    SET_PROPERTY(SOURCE ${ALL_AVXVNNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX2 ")
    SET_PROPERTY(SOURCE ${ALL_AVXVNNIINT8_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX2 ")
    SET_PROPERTY(SOURCE ${ALL_AVX256SKX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX512 ")
    SET_PROPERTY(SOURCE ${ALL_AVX256VNNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX512 ")
    SET_PROPERTY(SOURCE ${ALL_AVX256VNNIGFNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " /arch:AVX512 ")
    IF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
      SET_PROPERTY(SOURCE ${ALL_SSE_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-msse -clang:-mno-sse2 ")
      SET_PROPERTY(SOURCE ${ALL_SSE2_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-msse2 -clang:-mno-sse3 ")
      SET_PROPERTY(SOURCE ${ALL_SSSE3_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mssse3 -clang:-mno-sse4.1 ")
      SET_PROPERTY(SOURCE ${ALL_SSE41_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-msse4.1 -clang:-mno-sse4.2 ")
      SET_PROPERTY(SOURCE ${ALL_AVX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mavx -clang:-mno-avx2 -clang:-mno-fma -clang:-mno-f16c ")
      SET_PROPERTY(SOURCE ${ALL_F16C_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mno-avx2 -clang:-mno-fma ")
      SET_PROPERTY(SOURCE ${ALL_FMA3_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mno-avx2 ")
      SET_PROPERTY(SOURCE ${ALL_AVX2_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mavx2 ")
      SET_PROPERTY(SOURCE ${ALL_AVXVNNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mavx2 -clang:-mavxvnni ")
      SET_PROPERTY(SOURCE ${ALL_AVXVNNIINT8_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mavx2 -clang:-mavxvnniint8 ")
      SET_PROPERTY(SOURCE ${ALL_AVX256SKX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mavx512f -clang:-mavx512cd -clang:-mavx512bw -clang:-mavx512dq -clang:-mavx512vl ")
      SET_PROPERTY(SOURCE ${ALL_AVX256VNNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mavx512f -clang:-mavx512cd -clang:-mavx512bw -clang:-mavx512dq -clang:-mavx512vl -clang:-mavx512vnni ")
      SET_PROPERTY(SOURCE ${ALL_AVX256VNNIGFNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mavx512f -clang:-mavx512cd -clang:-mavx512bw -clang:-mavx512dq -clang:-mavx512vl -clang:-mavx512vnni -clang:-mgfni ")
      SET_PROPERTY(SOURCE ${ALL_AVX512F_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mavx512f ")
      SET_PROPERTY(SOURCE ${ALL_AVX512SKX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mavx512f -clang:-mavx512cd -clang:-mavx512bw -clang:-mavx512dq -clang:-mavx512vl ")
      SET_PROPERTY(SOURCE ${ALL_AVX512VBMI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mavx512f -clang:-mavx512cd -clang:-mavx512bw -clang:-mavx512dq -clang:-mavx512vl -clang:-mavx512vbmi ")
      SET_PROPERTY(SOURCE ${ALL_AVX512VNNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mavx512f -clang:-mavx512cd -clang:-mavx512bw -clang:-mavx512dq -clang:-mavx512vl -clang:-mavx512vnni ")
      SET_PROPERTY(SOURCE ${ALL_AVX512VNNIGFNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mavx512f -clang:-mavx512cd -clang:-mavx512bw -clang:-mavx512dq -clang:-mavx512vl -clang:-mavx512vnni -clang:-mgfni ")
      SET_PROPERTY(SOURCE ${ALL_AVX512FP16_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mavx512f -clang:-mavx512cd -clang:-mavx512bw -clang:-mavx512dq -clang:-mavx512vl -clang:-mavx512vnni -clang:-mgfni -clang:-mavx512fp16 ")
      SET_PROPERTY(SOURCE ${ALL_AVX512AMX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -clang:-mf16c -clang:-mfma -clang:-mavx512f -clang:-mavx512cd -clang:-mavx512bw -clang:-mavx512dq -clang:-mavx512vl -clang:-mavx512vnni -clang:-mgfni -clang:-mamx-tile -clang:-mamx-int8 ")
    ENDIF()
  ELSE()
    SET_PROPERTY(SOURCE ${ALL_SSE_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -msse -mno-sse2 ")
    SET_PROPERTY(SOURCE ${ALL_SSE2_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -msse2 -mno-sse3 ")
    SET_PROPERTY(SOURCE ${ALL_SSSE3_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mssse3 -mno-sse4.1 ")
    SET_PROPERTY(SOURCE ${ALL_SSE41_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -msse4.1 -mno-sse4.2 ")
    SET_PROPERTY(SOURCE ${ALL_AVX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx -mno-avx2 -mno-fma -mno-f16c ")
    SET_PROPERTY(SOURCE ${ALL_F16C_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mno-avx2 -mno-fma ")
    SET_PROPERTY(SOURCE ${ALL_FMA3_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mno-avx2 ")
    SET_PROPERTY(SOURCE ${ALL_AVX2_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mavx2 ")
    SET_PROPERTY(SOURCE ${ALL_AVXVNNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mavx2 -mavxvnni ")
    SET_PROPERTY(SOURCE ${ALL_AVXVNNIINT8_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mavx2 -mavxvnniint8 ")
    SET_PROPERTY(SOURCE ${ALL_AVX256SKX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl ")
    SET_PROPERTY(SOURCE ${ALL_AVX256VNNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl -mavx512vnni ")
    SET_PROPERTY(SOURCE ${ALL_AVX256VNNIGFNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl -mavx512vnni -mgfni ")
    SET_PROPERTY(SOURCE ${ALL_AVX512F_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx512f ")
    SET_PROPERTY(SOURCE ${ALL_AVX512SKX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl ")
    SET_PROPERTY(SOURCE ${ALL_AVX512VBMI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl -mavx512vbmi ")
    SET_PROPERTY(SOURCE ${ALL_AVX512VNNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl -mavx512vnni ")
    SET_PROPERTY(SOURCE ${ALL_AVX512VNNIGFNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl -mavx512vnni -mgfni ")
    SET_PROPERTY(SOURCE ${ALL_AVX512FP16_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl -mavx512vnni -mgfni -mavx512fp16 ")
    SET_PROPERTY(SOURCE ${ALL_AVX512AMX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -mf16c -mfma -mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl -mavx512vnni -mgfni -mamx-tile -mamx-int8 ")
    IF(MINGW OR CMAKE_SYSTEM_NAME MATCHES "^(CYGWIN|MSYS)$")
      # Work-around for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65782
      SET_PROPERTY(SOURCE ${ALL_AVX512F_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-asynchronous-unwind-tables ")
      SET_PROPERTY(SOURCE ${ALL_AVX512SKX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-asynchronous-unwind-tables ")
      SET_PROPERTY(SOURCE ${ALL_AVX512VBMI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-asynchronous-unwind-tables ")
      SET_PROPERTY(SOURCE ${ALL_AVX512VNNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-asynchronous-unwind-tables ")
      SET_PROPERTY(SOURCE ${ALL_AVXVNNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-asynchronous-unwind-tables ")
      SET_PROPERTY(SOURCE ${ALL_AVXVNNIINT8_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-asynchronous-unwind-tables ")
      SET_PROPERTY(SOURCE ${ALL_AVX256SKX_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-asynchronous-unwind-tables ")
      SET_PROPERTY(SOURCE ${ALL_AVX256VNNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-asynchronous-unwind-tables ")
      SET_PROPERTY(SOURCE ${ALL_AVX256VNNIGFNI_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-asynchronous-unwind-tables ")
    ENDIF()
  ENDIF()
ENDIF()

# Set `XNN_LOG_LEVEL` transitively for all targets that depend on `logging`.
TARGET_COMPILE_DEFINITIONS(logging PUBLIC "XNN_LOG_LEVEL=$<$<CONFIG:Debug>:5>$<$<NOT:$<CONFIG:Debug>>:0>")

IF(MSVC)
  # Even though MSVC has __restrict, it can't be used in all the same contexts as the C99 restrict keyword
  TARGET_COMPILE_DEFINITIONS(xnnpack-base INTERFACE "restrict=")

  IF(XNNPACK_BUILD_ALL_MICROKERNELS)
    TARGET_COMPILE_OPTIONS(microkernels-all PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O2>")
  ENDIF()
  TARGET_COMPILE_OPTIONS(microkernels-prod PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O2>")
  TARGET_COMPILE_OPTIONS(hardware-config PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O2>")
  TARGET_COMPILE_OPTIONS(indirection PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O2>")
  TARGET_COMPILE_OPTIONS(microparams-init PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O2>")
  TARGET_COMPILE_OPTIONS(normalization PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O1>")
  TARGET_COMPILE_OPTIONS(packing PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O2>")
  IF(XNNPACK_BUILD_LIBRARY)
    TARGET_COMPILE_OPTIONS(microkernel-utils PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O2>")
    TARGET_COMPILE_OPTIONS(operator-run PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O2>")
    TARGET_COMPILE_OPTIONS(operator-utils PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O2>")
    TARGET_COMPILE_OPTIONS(cache PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O1>")
    TARGET_COMPILE_OPTIONS(mutex PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O1>")
    TARGET_COMPILE_OPTIONS(subgraph PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O1>")
    TARGET_COMPILE_OPTIONS(operators PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O1>")
    TARGET_COMPILE_OPTIONS(XNNPACK PRIVATE "$<$<NOT:$<CONFIG:Debug>>:/O1>")
  ENDIF()
ELSE()
  TARGET_COMPILE_OPTIONS(xnnpack-base INTERFACE "$<$<NOT:$<CONFIG:Debug>>:-O2>")
  IF(XNNPACK_BUILD_ALL_MICROKERNELS)
    TARGET_COMPILE_OPTIONS(microkernels-all PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O2>")
  ENDIF()
  TARGET_COMPILE_OPTIONS(microkernels-prod PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O2>")
  TARGET_COMPILE_OPTIONS(hardware-config PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O2>")
  TARGET_COMPILE_OPTIONS(indirection PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O2>")
  TARGET_COMPILE_OPTIONS(microparams-init PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O2>")
  TARGET_COMPILE_OPTIONS(normalization PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-Os>")
  TARGET_COMPILE_OPTIONS(packing PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O2>")
  IF(XNNPACK_BUILD_LIBRARY)
    TARGET_COMPILE_OPTIONS(microkernel-utils PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O2>")
    TARGET_COMPILE_OPTIONS(operator-run PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O2>")
    TARGET_COMPILE_OPTIONS(operator-utils PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O2>")
    TARGET_COMPILE_OPTIONS(cache PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-Os>")
    TARGET_COMPILE_OPTIONS(mutex PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-Os>")
    TARGET_COMPILE_OPTIONS(subgraph PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-Os>")
    TARGET_COMPILE_OPTIONS(operators PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-Os>")
    TARGET_COMPILE_OPTIONS(XNNPACK PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-Os>")
  ENDIF()
ENDIF()

IF(XNNPACK_BUILD_ALL_MICROKERNELS)
  TARGET_INCLUDE_DIRECTORIES(microkernels-all PRIVATE include src)
ENDIF()
TARGET_INCLUDE_DIRECTORIES(datatype PRIVATE include src)
TARGET_INCLUDE_DIRECTORIES(microkernels-prod PRIVATE include src)
TARGET_INCLUDE_DIRECTORIES(hardware-config PRIVATE include src ${CPUINFO_SOURCE_DIR}/include)
TARGET_INCLUDE_DIRECTORIES(indirection PRIVATE include src)
TARGET_INCLUDE_DIRECTORIES(microparams-init PRIVATE include src)
TARGET_INCLUDE_DIRECTORIES(normalization PRIVATE include src)
TARGET_INCLUDE_DIRECTORIES(packing PRIVATE include src)
TARGET_INCLUDE_DIRECTORIES(logging PRIVATE include src)
IF(XNNPACK_BUILD_LIBRARY)
  TARGET_INCLUDE_DIRECTORIES(XNNPACK PUBLIC include)
  TARGET_INCLUDE_DIRECTORIES(XNNPACK PRIVATE src)
  TARGET_INCLUDE_DIRECTORIES(allocator PRIVATE include src)
  TARGET_INCLUDE_DIRECTORIES(cache PRIVATE include src)
  TARGET_INCLUDE_DIRECTORIES(microkernel-utils PRIVATE include src)
  TARGET_INCLUDE_DIRECTORIES(subgraph PRIVATE include src)
  TARGET_INCLUDE_DIRECTORIES(operators PRIVATE include src)
  TARGET_INCLUDE_DIRECTORIES(operator-run PRIVATE include src)
  TARGET_INCLUDE_DIRECTORIES(operator-utils PRIVATE include src)
  TARGET_INCLUDE_DIRECTORIES(reference-ukernels PRIVATE include src)
  TARGET_INCLUDE_DIRECTORIES(memory PRIVATE include src)
  TARGET_INCLUDE_DIRECTORIES(mutex PRIVATE include src)
  IF(WIN32)
    # Target Windows 7+ API
    TARGET_COMPILE_DEFINITIONS(XNNPACK PRIVATE _WIN32_WINNT=0x0601)
    TARGET_COMPILE_DEFINITIONS(mutex PRIVATE _WIN32_WINNT=0x0601)
  ENDIF()
  SET_PROPERTY(TARGET XNNPACK PROPERTY PUBLIC_HEADER include/xnnpack.h include/experiments-config.h)
ENDIF()

# ---[ Find libm
IF(XNNPACK_BUILD_WITH_LIBM)
  FIND_LIBRARY(LIBM m)
  IF(LIBM)
    IF(XNNPACK_BUILD_ALL_MICROKERNELS)
      TARGET_LINK_LIBRARIES(microkernels-all PRIVATE ${LIBM})
    ENDIF()
    TARGET_LINK_LIBRARIES(microkernels-prod PRIVATE ${LIBM})
    TARGET_LINK_LIBRARIES(hardware-config PRIVATE ${LIBM})
    TARGET_LINK_LIBRARIES(indirection PRIVATE ${LIBM})
    TARGET_LINK_LIBRARIES(subgraph PRIVATE ${LIBM})
    IF(XNNPACK_BUILD_LIBRARY)
      TARGET_LINK_LIBRARIES(XNNPACK PRIVATE ${LIBM})
    ENDIF()
  ENDIF()
ENDIF()

# ---[ Configure cpuinfo
IF(NOT TARGET cpuinfo)
  IF(NOT XNNPACK_USE_SYSTEM_LIBS)
    SET(CPUINFO_BUILD_TOOLS OFF CACHE BOOL "")
    SET(CPUINFO_BUILD_UNIT_TESTS OFF CACHE BOOL "")
    SET(CPUINFO_BUILD_MOCK_TESTS OFF CACHE BOOL "")
    SET(CPUINFO_BUILD_BENCHMARKS OFF CACHE BOOL "")
    ADD_SUBDIRECTORY(
      "${CPUINFO_SOURCE_DIR}"
      "${CMAKE_BINARY_DIR}/cpuinfo")
  ELSE()
    ADD_LIBRARY(cpuinfo SHARED IMPORTED)
    FIND_LIBRARY(CPUINFO_LIBRARY cpuinfo PATHS "${CPUINFO_SOURCE_DIR}/lib")
    IF(NOT CPUINFO_LIBRARY)
      MESSAGE(FATAL_ERROR "Cannot find cpuinfo")
    ENDIF()
    TARGET_INCLUDE_DIRECTORIES(cpuinfo INTERFACE "${CPUINFO_SOURCE_DIR}/include")
    SET_PROPERTY(TARGET cpuinfo PROPERTY IMPORTED_LOCATION "${CPUINFO_LIBRARY}")
    SET_PROPERTY(TARGET cpuinfo PROPERTY IMPORTED_IMPLIB "${CPUINFO_LIBRARY}")
  ENDIF()
ENDIF()
IF(XNNPACK_BUILD_LIBRARY)
  TARGET_LINK_LIBRARIES(hardware-config PRIVATE cpuinfo)
  TARGET_LINK_LIBRARIES(XNNPACK PRIVATE cpuinfo)
ENDIF()

# ---[ Configure pthreadpool
IF(NOT TARGET pthreadpool)
  IF(NOT XNNPACK_USE_SYSTEM_LIBS)
    SET(PTHREADPOOL_BUILD_TESTS OFF CACHE BOOL "")
    SET(PTHREADPOOL_BUILD_BENCHMARKS OFF CACHE BOOL "")
    SET(PTHREADPOOL_ALLOW_DEPRECATED_API OFF CACHE BOOL "")
    ADD_SUBDIRECTORY(
      "${PTHREADPOOL_SOURCE_DIR}"
      "${CMAKE_BINARY_DIR}/pthreadpool")
  ELSE()
    ADD_LIBRARY(pthreadpool SHARED IMPORTED)
    FIND_LIBRARY(PTHREADPOOL_LIBRARY pthreadpool PATHS "${PTHREADPOOL_SOURCE_DIR}/lib")
    IF(NOT PTHREADPOOL_LIBRARY)
      MESSAGE(FATAL_ERROR "Cannot find pthreadpool")
    ENDIF()
    FIND_PACKAGE(Threads REQUIRED)
    TARGET_INCLUDE_DIRECTORIES(pthreadpool INTERFACE "${PTHREADPOOL_SOURCE_DIR}/include")
    TARGET_LINK_LIBRARIES(pthreadpool INTERFACE Threads::Threads)
    SET_PROPERTY(TARGET pthreadpool PROPERTY IMPORTED_LOCATION "${PTHREADPOOL_LIBRARY}")
    SET_PROPERTY(TARGET pthreadpool PROPERTY IMPORTED_IMPLIB "${PTHREADPOOL_LIBRARY}")
  ENDIF()
ENDIF()
TARGET_LINK_LIBRARIES(xnnpack-base INTERFACE pthreadpool)

# ---[ Configure FXdiv
IF(NOT TARGET fxdiv)
  IF(NOT XNNPACK_USE_SYSTEM_LIBS)
    SET(FXDIV_BUILD_TESTS OFF CACHE BOOL "")
    SET(FXDIV_BUILD_BENCHMARKS OFF CACHE BOOL "")
    ADD_SUBDIRECTORY(
      "${FXDIV_SOURCE_DIR}"
      "${CMAKE_BINARY_DIR}/FXdiv")
  ELSE()
    FIND_FILE(FXDIV_HDR fxdiv.h PATH_SUFFIXES include PATHS "${FXDIV_SOURCE_DIR}")
    IF(NOT FXDIV_HDR)
      MESSAGE(FATAL_ERROR "Cannot find fxdiv")
    ENDIF()
    ADD_LIBRARY(fxdiv STATIC "${FXDIV_HDR}")
    TARGET_INCLUDE_DIRECTORIES(fxdiv INTERFACE "${FXDIV_SOURCE_DIR}/include")
    SET_PROPERTY(TARGET fxdiv PROPERTY LINKER_LANGUAGE C)
  ENDIF()
ENDIF()
IF(XNNPACK_BUILD_ALL_MICROKERNELS)
  TARGET_LINK_LIBRARIES(microkernels-all PRIVATE fxdiv)
ENDIF()
TARGET_LINK_LIBRARIES(microkernels-prod PRIVATE fxdiv)
TARGET_LINK_LIBRARIES(indirection PRIVATE fxdiv)
IF(XNNPACK_BUILD_LIBRARY)
  TARGET_LINK_LIBRARIES(XNNPACK PRIVATE fxdiv)
ENDIF()

IF(XNNPACK_BUILD_LIBRARY)
  INSTALL(TARGETS XNNPACK microkernels-prod
      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
      PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
ENDIF()

# ---[ Configure KleidiAI
IF(XNNPACK_ENABLE_KLEIDIAI)
  IF(NOT TARGET kleidiai)
    IF(NOT XNNPACK_USE_SYSTEM_LIBS)
      SET(KLEIDIAI_BUILD_TESTS OFF CACHE BOOL "")
      ADD_SUBDIRECTORY(
        "${KLEIDIAI_SOURCE_DIR}"
        "${CMAKE_BINARY_DIR}/kleidiai")
    ELSE()
      ADD_LIBRARY(kleidiai SHARED IMPORTED)
      FIND_LIBRARY(KLEIDIAI_LIBRARY kleidiai PATHS "${KLEIDIAI_SOURCE_DIR}/lib")
      IF(NOT KLEIDIAI_LIBRARY)
        MESSAGE(FATAL_ERROR "Cannot find KleidiAI")
      ENDIF()
      TARGET_INCLUDE_DIRECTORIES(kleidiai INTERFACE "${KLEIDIAI_SOURCE_DIR}")
      SET_PROPERTY(TARGET kleidiai PROPERTY IMPORTED_LOCATION "${KLEIDIAI_LIBRARY}")
      SET_PROPERTY(TARGET kleidiai PROPERTY IMPORTED_IMPLIB "${KLEIDIAI_LIBRARY}")
    ENDIF()
  ENDIF()
  TARGET_LINK_LIBRARIES(xnnpack-base INTERFACE kleidiai)
ENDIF()

# ---[ XNNPACK unit tests
IF(XNNPACK_BUILD_TESTS)
  # ---[ Macro to shard a test.
  MACRO(SHARD_TEST TEST_NAME NUM_SHARDS)
    SET_PROPERTY(
        TEST ${TEST_NAME}
          APPEND
          PROPERTY ENVIRONMENT "GTEST_TOTAL_SHARDS=${NUM_SHARDS};"
                  "GTEST_SHARD_INDEX=0")
    SET_PROPERTY(
        TEST ${TEST_NAME} PROPERTY COST 1000.0)
    math(EXPR NUM_SHARDS_MINUS_ONE "${NUM_SHARDS} - 1")
    FOREACH(SHARD RANGE 1 ${NUM_SHARDS_MINUS_ONE})
      ADD_TEST(NAME ${TEST_NAME}-${SHARD} COMMAND ${TEST_NAME})
      SET_PROPERTY(
          TEST ${TEST_NAME}-${SHARD}
            APPEND
            PROPERTY ENVIRONMENT "GTEST_TOTAL_SHARDS=${NUM_SHARDS};"
                    "GTEST_SHARD_INDEX=${SHARD}")
      SET_PROPERTY(
          TEST ${TEST_NAME}-${SHARD} PROPERTY COST 1000.0)
    ENDFOREACH()
  ENDMACRO()

  # ---[ Build google test
  IF(NOT TARGET gtest)
    IF(XNNPACK_USE_SYSTEM_LIBS)
      FIND_PACKAGE(GTest REQUIRED)
    ELSE()
      SET(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
      ADD_SUBDIRECTORY(
        "${GOOGLETEST_SOURCE_DIR}"
        "${CMAKE_BINARY_DIR}/googletest")
    ENDIF()
  ENDIF()

  # Helper libraries
  ADD_LIBRARY(next-prime STATIC test/next_prime.cc)
  ADD_LIBRARY(runtime-flags STATIC test/runtime-flags.cc)
  TARGET_LINK_LIBRARIES(runtime-flags PRIVATE GTest::gtest)

  ADD_LIBRARY(gemm-microkernel-tester STATIC test/gemm-microkernel-tester.cc)
  TARGET_INCLUDE_DIRECTORIES(gemm-microkernel-tester PRIVATE include src test)
  TARGET_LINK_LIBRARIES(gemm-microkernel-tester PRIVATE xnnpack-base pthreadpool GTest::gtest)
  TARGET_LINK_LIBRARIES(gemm-microkernel-tester PRIVATE packing)
  IF(XNNPACK_ENABLE_KLEIDIAI)
    TARGET_LINK_LIBRARIES(gemm-microkernel-tester PRIVATE kleidiai)
  ENDIF()
  TARGET_LINK_LIBRARIES(gemm-microkernel-tester PUBLIC next-prime)

  ADD_LIBRARY(dwconv-microkernel-tester STATIC test/dwconv-microkernel-tester.cc)
  TARGET_INCLUDE_DIRECTORIES(dwconv-microkernel-tester PRIVATE include src test)
  TARGET_LINK_LIBRARIES(dwconv-microkernel-tester PRIVATE XNNPACK pthreadpool GTest::gtest)
  TARGET_LINK_LIBRARIES(dwconv-microkernel-tester PUBLIC next-prime)

  ADD_LIBRARY(vbinary-microkernel-tester STATIC test/vbinary-microkernel-tester.cc)
  SET_TARGET_PROPERTIES(vbinary-microkernel-tester PROPERTIES CXX_EXTENSIONS YES)
  TARGET_INCLUDE_DIRECTORIES(vbinary-microkernel-tester PRIVATE include src test)
  TARGET_LINK_LIBRARIES(vbinary-microkernel-tester PRIVATE XNNPACK pthreadpool GTest::gtest)

  ADD_LIBRARY(unary-ops STATIC test/unary-ops.cc)
  TARGET_INCLUDE_DIRECTORIES(unary-ops PRIVATE include src test)
  TARGET_LINK_LIBRARIES(unary-ops PRIVATE XNNPACK)

  ADD_LIBRARY(convolution-test-helpers OBJECT test/convolution-test-helpers.cc)
  TARGET_INCLUDE_DIRECTORIES(convolution-test-helpers PRIVATE include src)
  TARGET_LINK_LIBRARIES(convolution-test-helpers PRIVATE xnnpack-base)

  ADD_LIBRARY(packq-microkernel-tester STATIC test/packq-microkernel-tester.cc)
  TARGET_INCLUDE_DIRECTORIES(packq-microkernel-tester PRIVATE include src test)
  TARGET_LINK_LIBRARIES(packq-microkernel-tester PRIVATE XNNPACK pthreadpool  GTest::gtest)
  IF(XNNPACK_ENABLE_KLEIDIAI)
    TARGET_LINK_LIBRARIES(packq-microkernel-tester PRIVATE kleidiai)
  ENDIF()

  IF(XNNPACK_BUILD_LIBRARY)
    # ---[ Build size tests
    ADD_EXECUTABLE(subgraph-size-test test/subgraph-size.c)
    TARGET_LINK_LIBRARIES(subgraph-size-test PRIVATE XNNPACK)

    # ---[ Build operator-level unit tests
    SET(LIBRARY_OPERATOR_TESTS
      batch-matrix-multiply-nc
      deconvolution-nhwc
      fully-connected-nc
      binary-elementwise-nd
      unary-elementwise-nc
    )
    FOREACH(TEST ${LIBRARY_OPERATOR_TESTS})
      ADD_EXECUTABLE(${TEST}-test test/${TEST}.cc)
      TARGET_INCLUDE_DIRECTORIES(${TEST}-test PRIVATE src test)
      TARGET_LINK_LIBRARIES(${TEST}-test PRIVATE
        GTest::gmock
        GTest::gtest
        GTest::gtest_main
        hardware-config
        logging
        microkernels-all
        microparams-init
        next-prime
        pthreadpool
        runtime-flags
        unary-ops
        XNNPACK)
      ADD_TEST(NAME ${TEST}-test COMMAND ${TEST}-test)
    ENDFOREACH()
    SHARD_TEST(batch-matrix-multiply-nc-test 10)
    SHARD_TEST(deconvolution-nhwc-test 10)
    SHARD_TEST(fully-connected-nc-test 10)
    SHARD_TEST(binary-elementwise-nd-test 30)

    # ---[ Build subgraph optimizations unit tests
    SET(LIBRARY_SUBGRAPH_OPTIMIZATION_TESTS
        fusion
        memory-planner
        subgraph-fp16
        subgraph
        runtime
        subgraph-nchw
        workspace)
    FOREACH(TEST ${LIBRARY_SUBGRAPH_OPTIMIZATION_TESTS})
      ADD_EXECUTABLE(${TEST}-test test/${TEST}.cc)
      TARGET_INCLUDE_DIRECTORIES(${TEST}-test PRIVATE src test)
      TARGET_LINK_LIBRARIES(${TEST}-test PRIVATE
        GTest::gmock
        GTest::gtest
        GTest::gtest_main
        runtime-flags
        XNNPACK)
      ADD_TEST(NAME ${TEST}-test COMMAND ${TEST}-test)
    ENDFOREACH()

    # ---[ Build subgraph-level unit tests
    SET(LIBRARY_SUBGRAPH_UNIT_TESTS
        argmax-pooling-2d
        average-pooling-2d
        average-pooling-2d-reshape
        batch-matrix-multiply
        binary
        concatenate2
        concatenate3
        concatenate4
        concatenate5
        copy
        depth-to-space-2d
        even-split2
        even-split3
        even-split4
        fully-connected
        global-average-pooling-1d
        global-average-pooling-2d
        global-sum-pooling-1d
        global-sum-pooling-2d
        max-pooling-2d
        reshape-helpers
        scaled-dot-product-attention
        static-slice
        softmax
        space-to-depth-2d
        static-constant-pad
        static-reduce
        static-reshape
        static-resize-bilinear-2d
        static-transpose
        transpose-reshape
        unary
        unpooling-2d)
    FOREACH(TEST ${LIBRARY_SUBGRAPH_UNIT_TESTS})
      ADD_EXECUTABLE(${TEST}-test test/${TEST}.cc)
      TARGET_INCLUDE_DIRECTORIES(${TEST}-test PRIVATE src test)
      TARGET_LINK_LIBRARIES(${TEST}-test PRIVATE
        GTest::gmock
        GTest::gtest
        GTest::gtest_main
        datatype
        subgraph
        logging
        runtime-flags
        unary-ops
        XNNPACK)
      ADD_TEST(NAME ${TEST}-test COMMAND ${TEST}-test)
      SET_TARGET_PROPERTIES(${TEST}-test PROPERTIES CXX_EXTENSIONS YES)
    ENDFOREACH()

    SET(LIBRARY_SUBGRAPH_CONVOLUTION_UNIT_TESTS
        convolution-2d
        deconvolution-2d
        depthwise-convolution-2d)
    FOREACH(TEST ${LIBRARY_SUBGRAPH_CONVOLUTION_UNIT_TESTS})
      ADD_EXECUTABLE(${TEST}-test test/${TEST}.cc)
      TARGET_INCLUDE_DIRECTORIES(${TEST}-test PRIVATE src test)
      TARGET_LINK_LIBRARIES(${TEST}-test PRIVATE
        convolution-test-helpers
        GTest::gmock
        GTest::gtest
        GTest::gtest_main
        runtime-flags
        subgraph
        XNNPACK)
      ADD_TEST(NAME ${TEST}-test COMMAND ${TEST}-test)
      SET_TARGET_PROPERTIES(${TEST}-test PROPERTIES CXX_EXTENSIONS YES)
    ENDFOREACH()
    SHARD_TEST(deconvolution-2d-test 10)
  ENDIF()

  # ---[ Normalization unit tests
  SET(NORMALIZATION_UNIT_TESTS
      slice-normalization
      reduce-normalization
      transpose-normalization)
  FOREACH(TEST ${NORMALIZATION_UNIT_TESTS})
    ADD_EXECUTABLE(${TEST}-test test/${TEST}.cc)
    TARGET_INCLUDE_DIRECTORIES(${TEST}-test PRIVATE include src test)
    TARGET_LINK_LIBRARIES(${TEST}-test PRIVATE GTest::gtest GTest::gtest_main pthreadpool normalization)
    ADD_TEST(NAME ${TEST}-test COMMAND ${TEST}-test)
  ENDFOREACH()

  # ---[ Build microkernel-level unit tests
  SET(MICROKERNEL_UNIT_TESTS
      avgpool-minmax
      maxpool-minmax
      f16-conv-hwc2chw
      f16-f32acc-rdsum
      f16-f32acc-rsum
      f16-ibilinear
      f16-ibilinear-chw
      f16-raddstoreexpminusmax
      f16-rmax
      f16-rsum
      f16-spmm-minmax
      f16-vcmul
      f16-vmulcaddc-minmax
      f32-argmaxpool
      f32-conv-hwc
      f32-conv-hwc2chw
      f32-ibilinear
      f32-ibilinear-chw
      f32-raddexpminusmax
      f32-raddextexp
      f32-raddstoreexpminusmax
      f32-rdsum
      f32-rmax
      f32-rmin
      f32-rminmax
      f32-rsum
      f32-spmm-minmax
      f32-vcmul
      f32-vmulcaddc-minmax
      f32-vscaleexpminusmax
      f32-vscaleextexp
      indirection
      packing
      qs8-packw
      qs8-qc4w-packw
      qs8-rdsum-minmax-fp32
      qs8-rsum
      qu8-rdsum
      qu8-rsum
      qu8-vlrelu
      s8-ibilinear
      u8-ibilinear
      u8-lut32norm
      u8-rmax
      x16-packw
      x32-packb
      x32-packw
      x32-packx
      x32-unpool
      x8-lut
      x8-packw
      xN-transpose
      xx-fill
      xx-pad)
  FOREACH(TEST ${MICROKERNEL_UNIT_TESTS})
    ADD_EXECUTABLE(${TEST}-test test/${TEST}.cc)
    TARGET_INCLUDE_DIRECTORIES(${TEST}-test PRIVATE include src test)
    TARGET_LINK_LIBRARIES(${TEST}-test PRIVATE
        GTest::gmock
        GTest::gtest
        GTest::gtest_main
        hardware-config
        indirection
        logging
        microkernels-all
        microkernel-utils
        microparams-init
        next-prime
        packing
        pthreadpool
        XNNPACK
    )
    ADD_TEST(NAME ${TEST}-test COMMAND ${TEST}-test)
    SET_TARGET_PROPERTIES(${TEST}-test PROPERTIES CXX_EXTENSIONS YES)
  ENDFOREACH()
  SHARD_TEST(avgpool-minmax-test 10)
  SHARD_TEST(maxpool-minmax-test 10)
  IF(XNNPACK_TARGET_PROCESSOR MATCHES "^riscv")
    SHARD_TEST(f32-argmaxpool-test 10)
    SHARD_TEST(f32-rdsum-test 10)
  ENDIF()

  SET(MICROKERNEL_DWCONV_UNIT_TESTS
      f16-dwconv-minmax-multipass
      f16-dwconv-minmax-unipass
      f16-dwconv2d-chw
      f32-dwconv-minmax-multipass
      f32-dwconv-minmax-unipass
      f32-dwconv-multipass
      f32-dwconv-unipass
      f32-dwconv2d-chw
      qs8-dwconv-minmax-multipass-fp32
      qs8-dwconv-minmax-multipass-rndnu
      qs8-dwconv-minmax-unipass-fp32
      qs8-dwconv-minmax-unipass-rndnu
      qs8-qc8w-dwconv-minmax-multipass-fp32
      qs8-qc8w-dwconv-minmax-unipass-fp32
      qu8-dwconv-minmax-multipass-fp32
      qu8-dwconv-minmax-multipass-rndnu
      qu8-dwconv-minmax-unipass-fp32
      qu8-dwconv-minmax-unipass-rndnu)
  FOREACH(TEST ${MICROKERNEL_DWCONV_UNIT_TESTS})
    ADD_EXECUTABLE(${TEST}-test test/${TEST}.cc)
    TARGET_INCLUDE_DIRECTORIES(${TEST}-test PRIVATE include src test)
    TARGET_LINK_LIBRARIES(${TEST}-test PRIVATE
        dwconv-microkernel-tester
        GTest::gmock
        GTest::gtest
        GTest::gtest_main
        hardware-config
        logging
        microkernels-all
        microparams-init
        pthreadpool
    )
    ADD_TEST(NAME ${TEST}-test COMMAND ${TEST}-test)
    SET_TARGET_PROPERTIES(${TEST}-test PROPERTIES CXX_EXTENSIONS YES)
  ENDFOREACH()
  SHARD_TEST(f16-dwconv-minmax-multipass-test 10)
  SHARD_TEST(qs8-dwconv-minmax-unipass-fp32-test 10)
  SHARD_TEST(qs8-qc8w-dwconv-minmax-unipass-fp32-test 10)
  SHARD_TEST(qu8-dwconv-minmax-multipass-fp32-test 10)
  SHARD_TEST(qs8-dwconv-minmax-multipass-fp32-test 10)
  SHARD_TEST(qs8-qc8w-dwconv-minmax-multipass-fp32-test 10)

  SET(MICROKERNEL_GEMM_UNIT_TESTS
      bf16-gemm-minmax
      f16-f32acc-gemm-minmax
      f16-f32acc-igemm-minmax
      f16-gemm-minmax
      f16-igemm-minmax
      f32-gemm
      f32-gemm-goi-minmax
      f32-gemm-minmax
      f32-gemm-relu
      f32-gemminc-minmax
      f32-igemm
      f32-igemm-minmax
      f32-igemm-relu
      f32-ppmm-minmax
      f32-qc4w-gemm-minmax
      f32-qc8w-gemm
      f32-qc8w-gemm-minmax
      f32-qc8w-gemm-relu
      qd8-f16-qb4w-gemm-minmax
      qd8-f16-qc4w-gemm-minmax
      qd8-f16-qc8w-gemm-minmax
      qd8-f32-qb4w-gemm-minmax
      qd8-f32-qc4w-gemm-minmax
      qd8-f32-qc8w-gemm-minmax
      qd8-f32-qc8w-igemm-minmax
      qp8-f32-qb4w-gemm-minmax
      qp8-f32-qc4w-gemm-minmax
      qp8-f32-qc8w-gemm-minmax
      qs8-qc8w-gemm-minmax-fp32
      qs8-qc8w-igemm-minmax-fp32
      qu8-gemm-minmax-fp32
      qu8-gemm-minmax-rndnu
      qu8-igemm-minmax-fp32
      qu8-igemm-minmax-rndnu)
  FOREACH(TEST ${MICROKERNEL_GEMM_UNIT_TESTS})
    FILE(GLOB TEST_SOURCES "test/${TEST}*.cc")
    IF(TEST_SOURCES)
        ADD_EXECUTABLE(${TEST}-test ${TEST_SOURCES})
        TARGET_INCLUDE_DIRECTORIES(${TEST}-test PRIVATE include src test)
        TARGET_LINK_LIBRARIES(${TEST}-test PRIVATE
            gemm-microkernel-tester
            GTest::gmock
            GTest::gtest
            GTest::gtest_main
            hardware-config
            logging
            microkernels-all
            microparams-init
            pthreadpool
        )
        ADD_TEST(NAME ${TEST}-test COMMAND ${TEST}-test)
        SET_TARGET_PROPERTIES(${TEST}-test PROPERTIES CXX_EXTENSIONS YES)
    ENDIF()
  ENDFOREACH()
  SHARD_TEST(qd8-f16-qc8w-gemm-minmax-test 10)
  SHARD_TEST(qd8-f32-qc4w-gemm-minmax-test 10)
  SHARD_TEST(qd8-f32-qc8w-gemm-minmax-test 10)
  SHARD_TEST(qd8-f32-qc8w-igemm-minmax-test 10)
  SHARD_TEST(qs8-qc8w-gemm-minmax-fp32-test 10)
  SHARD_TEST(qs8-qc8w-igemm-minmax-fp32-test 10)

  SET(MICROKERNEL_PACKQ_UNIT_TESTS
      x8-packq)
  FOREACH(TEST ${MICROKERNEL_PACKQ_UNIT_TESTS})
    ADD_EXECUTABLE(${TEST}-test test/${TEST}.cc)
    TARGET_INCLUDE_DIRECTORIES(${TEST}-test PRIVATE include src test)
    TARGET_LINK_LIBRARIES(${TEST}-test PRIVATE
        packq-microkernel-tester
        GTest::gmock
        GTest::gtest
        GTest::gtest_main
        hardware-config
        logging
        microkernels-all
        microparams-init
        pthreadpool
    )
    ADD_TEST(NAME ${TEST}-test COMMAND ${TEST}-test)
    SET_TARGET_PROPERTIES(${TEST}-test PROPERTIES CXX_EXTENSIONS YES)
  ENDFOREACH()

  SET(MICROKERNEL_VBINARY_UNIT_TESTS
      f16-vadd
      f16-vaddc
      f16-vdiv
      f16-vdivc
      f16-vmax
      f16-vmaxc
      f16-vmin
      f16-vminc
      f16-vmul
      f16-vmulc
      f16-vprelu
      f16-vpreluc
      f16-vrpreluc
      f16-vrdivc
      f16-vrsubc
      f16-vsqrdiff
      f16-vsqrdiffc
      f16-vsub
      f16-vsubc
      f32-vadd
      f32-vaddc
      f32-vcopysign
      f32-vcopysignc
      f32-vdiv
      f32-vdivc
      f32-vmax
      f32-vmaxc
      f32-vmin
      f32-vminc
      f32-vmul
      f32-vmulc
      f32-vprelu
      f32-vpreluc
      f32-vrpreluc
      f32-vrcopysignc
      f32-vrdivc
      f32-vrsubc
      f32-vsqrdiff
      f32-vsqrdiffc
      f32-vsub
      f32-vsubc
      qs8-vadd-minmax
      qs8-vaddc-minmax
      qs8-vmul-minmax-fp32
      qs8-vmulc-minmax-fp32
      qu8-vadd-minmax
      qu8-vaddc-minmax
      qu8-vmul-minmax-fp32
      qu8-vmul-minmax-rndnu
      qu8-vmulc-minmax-fp32
      qu8-vmulc-minmax-rndnu)
  FOREACH(TEST ${MICROKERNEL_VBINARY_UNIT_TESTS})
    ADD_EXECUTABLE(${TEST}-test test/${TEST}.cc)
    TARGET_INCLUDE_DIRECTORIES(${TEST}-test PRIVATE include src test)
    TARGET_LINK_LIBRARIES(${TEST}-test PRIVATE
        vbinary-microkernel-tester
        GTest::gmock
        GTest::gtest
        GTest::gtest_main
        hardware-config
        logging
        microkernels-all
        microparams-init
        pthreadpool
    )
    ADD_TEST(NAME ${TEST}-test COMMAND ${TEST}-test)
    SET_TARGET_PROPERTIES(${TEST}-test PROPERTIES CXX_EXTENSIONS YES)
  ENDFOREACH()

  SET(MICROKERNEL_VCVT_TESTS
      f16-f32-vcvt
      f16-qs8-vcvt
      f16-qu8-vcvt
      f32-f16-vcvt
      f32-qs8-vcvt
      f32-qu8-vcvt
      qs8-f16-vcvt
      qs8-f32-vcvt
      qs8-vcvt
      qu8-f32-vcvt
      qu8-vcvt)
  LIST(REMOVE_ITEM MICROKERNEL_VCVT_TESTS ${SHARDED_TESTS})
  FOREACH(TEST ${MICROKERNEL_VCVT_TESTS})
    ADD_EXECUTABLE(${TEST}-test test/${TEST}.cc)
    TARGET_INCLUDE_DIRECTORIES(${TEST}-test PRIVATE include src test)
    TARGET_LINK_LIBRARIES(${TEST}-test PRIVATE
        GTest::gmock
        GTest::gtest
        GTest::gtest_main
        hardware-config
        logging
        microkernels-all
        microparams-init
        pthreadpool
    )
    ADD_TEST(NAME ${TEST}-test COMMAND ${TEST}-test)
    SET_TARGET_PROPERTIES(${TEST}-test PROPERTIES CXX_EXTENSIONS YES)
  ENDFOREACH()
  IF(XNNPACK_TARGET_PROCESSOR MATCHES "^riscv")
    SHARD_TEST(f16-qs8-vcvt-test 10)
    SHARD_TEST(f16-qu8-vcvt-test 10)
    SHARD_TEST(f32-qs8-vcvt-test 10)
    SHARD_TEST(f32-qu8-vcvt-test 10)
    SHARD_TEST(qs8-f32-vcvt-test 10)
    SHARD_TEST(qu8-f32-vcvt-test 10)
    SHARD_TEST(qs8-vcvt-test 10)
    SHARD_TEST(qu8-vcvt-test 10)
  ENDIF()

  SET(MICROKERNEL_VUNARY_TESTS
      f16-vabs
      f16-vclamp
      f16-velu
      f16-vhswish
      f16-vlrelu
      f16-vneg
      f16-vrndd
      f16-vrndne
      f16-vrndu
      f16-vrndz
      f16-vrsqrt
      f16-vsigmoid
      f16-vsqr
      f16-vsqrt
      f16-vtanh
      f32-vabs
      f32-vclamp
      f32-velu
      f32-vexp
      f32-vgelu
      f32-vhswish
      f32-vlog
      f32-vlrelu
      f32-vneg
      f32-vrelu
      f32-vrndd
      f32-vrndne
      f32-vrndu
      f32-vrndz
      f32-vrsqrt
      f32-vsigmoid
      f32-vsqr
      f32-vsqrt
      f32-vtanh
      qs8-vlrelu
      s8-vclamp
      u8-vclamp)
  LIST(REMOVE_ITEM MICROKERNEL_VUNARY_TESTS ${SHARDED_TESTS})
  FOREACH(TEST ${MICROKERNEL_VUNARY_TESTS})
    ADD_EXECUTABLE(${TEST}-test test/${TEST}.cc)
    TARGET_INCLUDE_DIRECTORIES(${TEST}-test PRIVATE include src test)
    TARGET_LINK_LIBRARIES(${TEST}-test PRIVATE
        GTest::gmock
        GTest::gtest
        GTest::gtest_main
        hardware-config
        logging
        microkernels-all
        microparams-init
        pthreadpool
        next-prime
    )
    ADD_TEST(NAME ${TEST}-test COMMAND ${TEST}-test)
    SET_TARGET_PROPERTIES(${TEST}-test PROPERTIES CXX_EXTENSIONS YES)
  ENDFOREACH()
  IF(XNNPACK_TARGET_PROCESSOR MATCHES "^riscv")
    SHARD_TEST(f32-vclamp-test 10)
    SHARD_TEST(f32-velu-test 10)
    SHARD_TEST(f32-vlrelu-test 10)
    SHARD_TEST(qs8-vlrelu-test 10)
    SHARD_TEST(qu8-vlrelu-test 10)
    SHARD_TEST(s8-vclamp-test 10)
    SHARD_TEST(u8-vclamp-test 10)
  ENDIF()

  # Special-case
  IF(XNNPACK_ENABLE_KLEIDIAI)
    TARGET_LINK_LIBRARIES(x8-packq-test PRIVATE kleidiai)
  ENDIF()

  IF(XNNPACK_BUILD_LIBRARY)
    ADD_EXECUTABLE(weights-cache-test test/weights-cache.cc)
    TARGET_INCLUDE_DIRECTORIES(weights-cache-test PRIVATE include src)
    TARGET_LINK_LIBRARIES(weights-cache-test PRIVATE XNNPACK pthreadpool GTest::gtest GTest::gtest_main)

    ADD_EXECUTABLE(mutex-test test/mutex.cc)
    TARGET_INCLUDE_DIRECTORIES(mutex-test PRIVATE include src)
    TARGET_LINK_LIBRARIES(mutex-test PRIVATE GTest::gtest GTest::gtest_main pthreadpool)
    TARGET_LINK_LIBRARIES(mutex-test PRIVATE logging mutex)

    ADD_EXECUTABLE(microkernel-utils-test test/microkernel-utils.cc)
    TARGET_INCLUDE_DIRECTORIES(microkernel-utils-test PRIVATE include src)
    TARGET_LINK_LIBRARIES(microkernel-utils-test PRIVATE microkernel-utils hardware-config GTest::gtest GTest::gtest_main pthreadpool)

    ADD_EXECUTABLE(operator-utils-test test/operator-utils.cc)
    TARGET_INCLUDE_DIRECTORIES(operator-utils-test PRIVATE include src)
    TARGET_LINK_LIBRARIES(operator-utils-test PRIVATE XNNPACK GTest::gtest GTest::gtest_main pthreadpool)
  ENDIF()


  # ---[ Mark the operator tests as such.
  MACRO(get_all_test_targets_recursive test_targets dir)
    GET_PROPERTY(subdirectories DIRECTORY ${dir} PROPERTY SUBDIRECTORIES)
    FOREACH(subdir ${subdirectories})
      get_all_test_targets_recursive(${test_targets} ${subdir})
    ENDFOREACH()

    GET_PROPERTY(current_test_targets DIRECTORY ${dir} PROPERTY TESTS)
    LIST(APPEND ${test_targets} ${current_test_targets})
  ENDMACRO()

  FUNCTION(get_all_test_targets var)
    SET(test_targets)
    get_all_test_targets_recursive(test_targets ${CMAKE_CURRENT_SOURCE_DIR})
    SET(${var} ${test_targets} PARENT_SCOPE)
  ENDFUNCTION()

  get_all_test_targets(test_targets)
  LIST(FILTER test_targets INCLUDE REGEX "-(nc|nd|nd-eager|ncw|nhwc|nhtc|nchw|nwc)-test(-[0-9]+)?$")
  MESSAGE(STATUS "Inferred operator tests: ${test_targets}")
  SET_TESTS_PROPERTIES(${test_targets} PROPERTIES LABELS "operator")

ENDIF()

# ---[ XNNPACK microbenchmarks
IF(XNNPACK_BUILD_BENCHMARKS)
  # ---[ Build google benchmark
  IF(NOT TARGET benchmark)
    IF(XNNPACK_USE_SYSTEM_LIBS)
      FIND_PACKAGE(benchmark REQUIRED)
    ELSE()
      SET(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "")
      ADD_SUBDIRECTORY(
        "${GOOGLEBENCHMARK_SOURCE_DIR}"
        "${CONFU_DEPENDENCIES_BINARY_DIR}/googlebenchmark")
    ENDIF()
  ENDIF()

  ADD_LIBRARY(bench-utils STATIC bench/utils.cc)
  TARGET_INCLUDE_DIRECTORIES(bench-utils PUBLIC include src)
  TARGET_LINK_LIBRARIES(bench-utils PRIVATE benchmark::benchmark cpuinfo pthreadpool)
  TARGET_LINK_LIBRARIES(bench-utils PRIVATE xnnpack-base hardware-config)
  IF(XNNPACK_BUILD_LIBRARY)
    TARGET_LINK_LIBRARIES(bench-utils PRIVATE logging memory)
  ENDIF()

  # Helper libraries
  ADD_LIBRARY(packq-benchmark STATIC bench/packq-benchmark.cc)
  TARGET_INCLUDE_DIRECTORIES(packq-benchmark PRIVATE include src bench)
  TARGET_LINK_LIBRARIES(packq-benchmark PRIVATE XNNPACK benchmark::benchmark bench-utils)
  IF(XNNPACK_ENABLE_KLEIDIAI)
    TARGET_LINK_LIBRARIES(packq-benchmark PRIVATE kleidiai)
  ENDIF()

  ADD_LIBRARY(gemm-benchmark STATIC bench/gemm-benchmark.cc)
  TARGET_INCLUDE_DIRECTORIES(gemm-benchmark PRIVATE include src bench)
  TARGET_LINK_LIBRARIES(gemm-benchmark PRIVATE XNNPACK benchmark::benchmark bench-utils)
  IF(XNNPACK_ENABLE_KLEIDIAI)
    TARGET_LINK_LIBRARIES(gemm-benchmark PUBLIC kleidiai)
  ENDIF()

  ADD_LIBRARY(im2col STATIC src/im2col.c)
  TARGET_INCLUDE_DIRECTORIES(im2col PRIVATE src)

  IF(XNNPACK_BUILD_LIBRARY)
    # ---[ Build end-to-end microbenchmarks
    ADD_LIBRARY(models STATIC
      bench/models/fp32-attention.cc
      bench/models/fp32-mobilenet-v1.cc
      bench/models/fp32-mobilenet-v2.cc
      bench/models/fp32-mobilenet-v3-large.cc
      bench/models/fp32-mobilenet-v3-small.cc
      bench/models/qd8-attention.cc
      bench/models/qs8-mobilenet-v2.cc)
    SET_TARGET_PROPERTIES(models PROPERTIES CXX_EXTENSIONS YES)
    TARGET_LINK_LIBRARIES(models PRIVATE XNNPACK)

    ADD_EXECUTABLE(bench-models bench/models/benchmark.cc)
    TARGET_INCLUDE_DIRECTORIES(bench-models PRIVATE bench)
    TARGET_LINK_LIBRARIES(bench-models PRIVATE
      bench-utils
      benchmark::benchmark
      models
      XNNPACK)

    # ---[ Build operator-level microbenchmarks
    SET(LIBRARY_OPERATOR_BENCHMARKS
        average-pooling
        convolution
        deconvolution
        max-pooling
        softmax
        unary)
    FOREACH(BENCH ${LIBRARY_OPERATOR_BENCHMARKS})
      ADD_EXECUTABLE(${BENCH}-bench bench/${BENCH}.cc)
      TARGET_LINK_LIBRARIES(${BENCH}-bench PRIVATE
        bench-utils
        benchmark::benchmark
        datatype
        XNNPACK
      )
    ENDFOREACH()
  ENDIF()

  # ---[ Build microkernel-level microbenchmarks
  SET(MICROKERNEL_BENCHMARKS
      bf16-gemm
      f16-conv-hwc2chw
      f16-dwconv
      f16-dwconv2d-chw
      f16-f32acc-gemm
      f16-f32acc-igemm
      f16-f32acc-rdsum
      f16-f32acc-rsum
      f16-gemm
      f16-gemm-minmax
      f16-igemm
      f16-raddstoreexpminusmax
      f16-rmax
      f16-rmin
      f16-rminmax
      f16-rsum
      f16-spmm
      f32-bgemm
      f32-conv-hwc
      f32-conv-hwc2chw
      f32-dwconv
      f32-dwconv2d-chw
      f32-gemm
      f32-gemm-goi-minmax
      f32-gemm-minmax
      f32-igemm
      f32-im2col-gemm
      f32-qc4w-gemm
      f32-qc8w-gemm
      f32-raddexpminusmax
      f32-raddextexp
      f32-raddstoreexpminusmax
      f32-rdsum
      f32-rmax
      f32-rmin
      f32-rminmax
      f32-rsum
      f32-softmax
      f32-spmm
      f16-vcmul
      f32-vcmul
      f32-vscaleexpminusmax
      f32-vscaleextexp
      qd8-f16-qb4w-gemm
      qd8-f16-qc4w-gemm
      qd8-f16-qc8w-gemm
      qd8-f32-qb4w-gemm
      qd8-f32-qc4w-gemm
      qd8-f32-qc8w-gemm
      qp8-f32-qc4w-gemm
      qp8-f32-qc8w-gemm
      qp8-f32-qb4w-gemm
      qs8-dwconv
      qs8-gemm
      qs8-qc8w-gemm-fp32
      qu8-rdsum
      qs8-rsum
      qu8-rsum
      qu8-gemm
      qu8-gemm-fp32
      qu8-gemm-rndnu
      x16-packw
      x32-packw
      x8-lut
      x8-packq
      x8-packw
      vunary
      vbinary
      xN-transposec
      xx-transposev)
  FOREACH(BENCH ${MICROKERNEL_BENCHMARKS})
    ADD_EXECUTABLE(${BENCH}-bench bench/${BENCH}.cc)
    TARGET_INCLUDE_DIRECTORIES(${BENCH}-bench PRIVATE include src)
    TARGET_LINK_LIBRARIES(${BENCH}-bench PRIVATE
      bench-utils
      benchmark::benchmark
      gemm-benchmark
      hardware-config
      im2col
      indirection
      logging
      microkernels-all
      microparams-init
      packing
      packq-benchmark
      pthreadpool)
    SET_TARGET_PROPERTIES(${BENCH}-bench PROPERTIES CXX_EXTENSIONS YES)
  ENDFOREACH()

  # Special-case
  IF(XNNPACK_ENABLE_KLEIDIAI)
    TARGET_LINK_LIBRARIES(x8-packq-bench PRIVATE kleidiai)
  ENDIF()
ENDIF()
